CUTLASS 2.4 (Implicit GEMM convolution) (#147)
CUTLASS 2.4 (Implicit GEMM Convolution) Co-authored-by: Manish Gupta <manigupta@nvidia.com>, Haicheng Wu <haichengw@nvidia.com>, Dustyn Blasig <dblasig@nvidia.com>, Andrew Kerr <akerr@nvidia.com>
This commit is contained in:
co-authored by
Manish Gupta <manigupta@nvidia.com>, Haicheng Wu <haichengw@nvidia.com>, Dustyn Blasig <dblasig@nvidia.com>, Andrew Kerr <akerr@nvidia.com>
parent
c2b80ad4e4
commit
6615010cd0
@@ -26,6 +26,12 @@ if (CUTLASS_ENABLE_LIBRARY)
|
||||
add_subdirectory(library)
|
||||
endif()
|
||||
if (CUTLASS_ENABLE_PROFILER)
|
||||
add_subdirectory(profiler)
|
||||
if (NOT CUTLASS_ENABLE_LIBRARY)
|
||||
message(SEND_ERROR "Build conflict: The CUTLASS profiler requires the CUTLASS library.")
|
||||
message(SEND_ERROR " CUTLASS_ENABLE_PROFILER = ${CUTLASS_ENABLE_PROFILER}")
|
||||
message(SEND_ERROR " CUTLASS_ENABLE_LIBRARY = ${CUTLASS_ENABLE_LIBRARY}")
|
||||
else()
|
||||
add_subdirectory(profiler)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -63,6 +63,15 @@ cutlass_add_library(
|
||||
src/reference/gemm.cu
|
||||
src/reference/initialize_reference_operations.cu
|
||||
|
||||
|
||||
# cutlass reduction instances in cutlass library
|
||||
src/reduction/reduction_device.cu
|
||||
src/reduction/init_reduction_operations.cu
|
||||
|
||||
# cutlass conv reference instances in cutlass library
|
||||
src/reference/conv2d.cu
|
||||
src/reference/conv3d.cu
|
||||
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE GENERATOR_PYTHON_SOURCES CONFIGURE_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/scripts/*.py)
|
||||
@@ -136,7 +145,7 @@ function(cutlass_add_cutlass_library)
|
||||
cutlass_library_includes
|
||||
)
|
||||
|
||||
set_target_properties(${__NAME} PROPERTIES DEBUG_POSTFIX ${CUTLASS_LIBRARY_DEBUG_POSTFIX})
|
||||
set_target_properties(${__NAME} PROPERTIES DEBUG_POSTFIX "${CUTLASS_LIBRARY_DEBUG_POSTFIX}")
|
||||
|
||||
set(OUTPUT_NAME cutlass)
|
||||
|
||||
|
||||
@@ -335,6 +335,10 @@ public:
|
||||
using HandlePtr = std::unique_ptr<Handle>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Finds conv2d operation instances with Conv2d::ElementC = Reduction::ElementWorkspace
|
||||
Operation const* find_conv_operation_for_parallel_reduction(Operation const *operation);
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -53,6 +53,10 @@
|
||||
#include "cutlass/layout/tensor.h"
|
||||
|
||||
#include "cutlass/gemm/gemm.h"
|
||||
#include "cutlass/conv/convolution.h"
|
||||
#include "cutlass/conv/conv2d_problem_size.h"
|
||||
#include "cutlass/conv/conv3d_problem_size.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
@@ -79,6 +83,10 @@ enum class LayoutTypeID {
|
||||
kTensorNCDHW,
|
||||
kTensorNHWC,
|
||||
kTensorNDHWC,
|
||||
kTensorNC32HW32,
|
||||
kTensorC32RSK32,
|
||||
kTensorNC64HW64,
|
||||
kTensorC64RSK64,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
@@ -138,6 +146,7 @@ enum class Provider {
|
||||
kReferenceHost,
|
||||
kReferenceDevice,
|
||||
kCUBLAS,
|
||||
kCUDNN,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
@@ -146,6 +155,8 @@ enum class Provider {
|
||||
/// Enumeration indicating the kind of operation
|
||||
enum class OperationKind {
|
||||
kGemm,
|
||||
kConv2d,
|
||||
kConv3d,
|
||||
kEqGemm,
|
||||
kSparseGemm,
|
||||
kReduction,
|
||||
@@ -204,6 +215,30 @@ enum class GemmKind {
|
||||
/// Mode of Universal GEMM
|
||||
using GemmUniversalMode = cutlass::gemm::GemmUniversalMode;
|
||||
|
||||
/// Enumeration indicating what kind of Conv2d operation to perform
|
||||
enum class ConvKind {
|
||||
kUnknown,
|
||||
kFprop,
|
||||
kDgrad,
|
||||
kWgrad,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
enum class ConvModeID {
|
||||
kCrossCorrelation,
|
||||
kConvolution,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
// Iterator algorithm enum in order of general performance-efficiency
|
||||
enum class IteratorAlgorithmID {
|
||||
kNone,
|
||||
kAnalytic,
|
||||
kOptimized,
|
||||
kInvalid
|
||||
};
|
||||
|
||||
|
||||
enum class EpilogueKind {
|
||||
kUnknown,
|
||||
kConversion,
|
||||
@@ -477,6 +512,66 @@ struct ReductionDescription : public OperationDescription {
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Description of all Conv2d operations
|
||||
struct ConvDescription : public OperationDescription {
|
||||
/// Describes the convolution dimension support (2D or 3D)
|
||||
int conv_dim;
|
||||
|
||||
/// Describes the kind of convolution
|
||||
ConvKind conv_kind;
|
||||
|
||||
/// Describes the type of iterator algorithm (analytic or precomputed)
|
||||
IteratorAlgorithmID iterator_algorithm;
|
||||
|
||||
/// Describes the A operand
|
||||
TensorDescription A;
|
||||
|
||||
/// Describes the B operand
|
||||
TensorDescription B;
|
||||
|
||||
/// Describes the C operand
|
||||
TensorDescription C;
|
||||
|
||||
/// Describes the data type of the scalars passed to the epilogue
|
||||
NumericTypeID element_epilogue;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
// Returns Activation TensorDescription
|
||||
TensorDescription activation() const {
|
||||
switch(conv_kind) {
|
||||
case library::ConvKind::kFprop : return A;
|
||||
case library::ConvKind::kDgrad : return C;
|
||||
case library::ConvKind::kWgrad : return B;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns Filter TensorDescription
|
||||
TensorDescription filter() const {
|
||||
switch(conv_kind) {
|
||||
case library::ConvKind::kFprop : return B;
|
||||
case library::ConvKind::kDgrad : return B;
|
||||
case library::ConvKind::kWgrad : return C;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns Output TensorDescription
|
||||
TensorDescription output() const {
|
||||
switch(conv_kind) {
|
||||
case library::ConvKind::kFprop : return C;
|
||||
case library::ConvKind::kDgrad : return A;
|
||||
case library::ConvKind::kWgrad : return A;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Base class for all operations
|
||||
@@ -825,6 +920,204 @@ struct SparseGemmArguments {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Two dimensional convolution
|
||||
//
|
||||
// OperationKind: Conv2d
|
||||
//
|
||||
struct Conv2dConfiguration {
|
||||
|
||||
conv::SplitKMode split_k_mode;
|
||||
|
||||
/// Conv2d problem size
|
||||
// contains strictly conv2d size (N,H,W,C,K,R,S,P,Q,padding,stride,dilation,mode)
|
||||
// also includes (split_k_slices, groups)
|
||||
conv::Conv2dProblemSize problem_size;
|
||||
|
||||
/// Layout object for activations tensor
|
||||
layout::TensorNHWC layout_activations;
|
||||
|
||||
/// Layout object for filters tensor
|
||||
layout::TensorNHWC layout_filters;
|
||||
|
||||
/// Layout object for source tensor
|
||||
layout::TensorNHWC layout_source;
|
||||
|
||||
/// Layout object for output tensor
|
||||
layout::TensorNHWC layout_output;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
// Mapping functions (A,B,C -> activation,filter,output)
|
||||
layout::TensorNHWC layout_a(library::ConvKind const &conv_kind) const {
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return layout_activations;
|
||||
case library::ConvKind::kDgrad: return layout_output;
|
||||
case library::ConvKind::kWgrad: return layout_output;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
layout::TensorNHWC layout_b(library::ConvKind const &conv_kind) const {
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return layout_filters;
|
||||
case library::ConvKind::kDgrad: return layout_filters;
|
||||
case library::ConvKind::kWgrad: return layout_activations;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
layout::TensorNHWC layout_c(library::ConvKind const &conv_kind) const {
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return layout_output;
|
||||
case library::ConvKind::kDgrad: return layout_activations;
|
||||
case library::ConvKind::kWgrad: return layout_filters;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// Three dimensional convolution
|
||||
//
|
||||
// OperationKind: Conv3d
|
||||
//
|
||||
struct Conv3dConfiguration {
|
||||
|
||||
conv::SplitKMode split_k_mode;
|
||||
|
||||
/// Conv2d problem size
|
||||
// contains strictly conv2d size (N,D,H,W,C,K,T,R,S,Z,P,Q,padding,stride,dilation,mode)
|
||||
// also includes (split_k_slices, groups)
|
||||
conv::Conv3dProblemSize problem_size;
|
||||
|
||||
/// Layout object for activations tensor
|
||||
layout::TensorNDHWC layout_activations;
|
||||
|
||||
/// Layout object for filters tensor
|
||||
layout::TensorNDHWC layout_filters;
|
||||
|
||||
/// Layout object for source tensor
|
||||
layout::TensorNDHWC layout_source;
|
||||
|
||||
/// Layout object for output tensor
|
||||
layout::TensorNDHWC layout_output;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
// Mapping functions (A,B,C -> activation,filter,output)
|
||||
layout::TensorNDHWC layout_a(library::ConvKind const &conv_kind) const {
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return layout_activations;
|
||||
case library::ConvKind::kDgrad: return layout_output;
|
||||
case library::ConvKind::kWgrad: return layout_output;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
layout::TensorNDHWC layout_b(library::ConvKind const &conv_kind) const {
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return layout_filters;
|
||||
case library::ConvKind::kDgrad: return layout_filters;
|
||||
case library::ConvKind::kWgrad: return layout_activations;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
layout::TensorNDHWC layout_c(library::ConvKind const &conv_kind) const {
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return layout_output;
|
||||
case library::ConvKind::kDgrad: return layout_activations;
|
||||
case library::ConvKind::kWgrad: return layout_filters;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Arguments for CONV
|
||||
struct ConvArguments {
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
/// ImplicitGemm matrices A, B, C, D
|
||||
/////////////////////////////////////////////////////////
|
||||
/// pointer to implicit gemm matrix A
|
||||
void const *A;
|
||||
|
||||
/// pointer to implicit gemm matrix B
|
||||
void const *B;
|
||||
|
||||
/// pointer to implicit gemm matrix C
|
||||
void const *C;
|
||||
|
||||
/// pointer to implicit gemm desitination matrix D
|
||||
void *D;
|
||||
|
||||
/// Host or device pointer to alpha scalar
|
||||
void const *alpha;
|
||||
|
||||
/// Host or device pointer to beta scalar
|
||||
void const *beta;
|
||||
|
||||
/// Enumerant indicating whether alpha/beta point to host or device memory
|
||||
ScalarPointerMode pointer_mode;
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Configuration for Reduction operations
|
||||
//
|
||||
// OperationKind: Reduction
|
||||
//
|
||||
struct ReductionConfiguration {
|
||||
|
||||
/// Redcution problem size
|
||||
MatrixCoord problem_size;
|
||||
|
||||
/// Number of partitions to reduce
|
||||
int partitions;
|
||||
|
||||
/// Number of lements between each partition
|
||||
int64_t partition_stride;
|
||||
|
||||
/// leading dimension of 'w'orksace operand
|
||||
int64_t ldw;
|
||||
|
||||
/// leading dimension of 's'ource operand
|
||||
int64_t lds;
|
||||
|
||||
/// leading dimension of 'd'estination operand
|
||||
int64_t ldd;
|
||||
};
|
||||
|
||||
/// Arguments for Reduction
|
||||
struct ReductionArguments {
|
||||
|
||||
/// Pointer to workspace matrix
|
||||
void const *workspace;
|
||||
|
||||
/// Pointer to source matrix
|
||||
void const *source;
|
||||
|
||||
/// Pointer to destination matrix
|
||||
void *destination;
|
||||
|
||||
/// pointer to reference matrix
|
||||
void *reference;
|
||||
|
||||
/// Host or device pointer to alpha scalar
|
||||
void const *alpha;
|
||||
|
||||
/// Host or device pointer to beta scalar
|
||||
void const *beta;
|
||||
|
||||
/// Enumerant indicating whether alpha/beta point to host or device memory
|
||||
ScalarPointerMode pointer_mode;
|
||||
};
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
|
||||
@@ -51,6 +51,9 @@ class Manifest;
|
||||
// init and insert all cutlass gemm operations in manifest object (procedurally generated using generator.py)
|
||||
void initialize_all(Manifest &manifest);
|
||||
|
||||
// init and insert all reduction op in manifest object (manually instantiated in library/reduction)
|
||||
void initialize_all_reduction_op(Manifest &manifest);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// List of operations
|
||||
|
||||
@@ -208,6 +208,262 @@ using GemmOperationFunctionalMap = std::unordered_map<
|
||||
>;
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Data Structures for Conv Functional Maps
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Tuple uniquely identifying conv2d functional behavior
|
||||
struct ConvFunctionalKey {
|
||||
library::Provider provider;
|
||||
library::ConvKind conv_kind;
|
||||
library::NumericTypeID element_A;
|
||||
library::LayoutTypeID layout_A;
|
||||
library::NumericTypeID element_B;
|
||||
library::LayoutTypeID layout_B;
|
||||
library::NumericTypeID element_C;
|
||||
library::LayoutTypeID layout_C;
|
||||
library::NumericTypeID element_accumulator;
|
||||
library::NumericTypeID element_compute;
|
||||
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
inline
|
||||
ConvFunctionalKey(
|
||||
library::Provider provider = library::Provider::kInvalid,
|
||||
library::ConvKind conv_kind = library::ConvKind::kFprop,
|
||||
library::NumericTypeID element_A = library::NumericTypeID::kF16,
|
||||
library::LayoutTypeID layout_A = library::LayoutTypeID::kTensorNHWC,
|
||||
library::NumericTypeID element_B = library::NumericTypeID::kF16,
|
||||
library::LayoutTypeID layout_B = library::LayoutTypeID::kTensorNHWC,
|
||||
library::NumericTypeID element_C = library::NumericTypeID::kF16,
|
||||
library::LayoutTypeID layout_C = library::LayoutTypeID::kTensorNHWC,
|
||||
library::NumericTypeID element_accumulator = library::NumericTypeID::kF32,
|
||||
library::NumericTypeID element_compute = library::NumericTypeID::kF32
|
||||
):
|
||||
provider(provider),
|
||||
conv_kind(conv_kind),
|
||||
element_A(element_A),
|
||||
layout_A(layout_A),
|
||||
element_B(element_B),
|
||||
layout_B(layout_B),
|
||||
element_C(element_C),
|
||||
layout_C(layout_C),
|
||||
element_accumulator(element_accumulator),
|
||||
element_compute(element_compute)
|
||||
{ }
|
||||
|
||||
inline
|
||||
bool operator==(ConvFunctionalKey const &rhs) const {
|
||||
return
|
||||
(provider == rhs.provider) &&
|
||||
(conv_kind == rhs.conv_kind) &&
|
||||
(element_A == rhs.element_A) &&
|
||||
(layout_A == rhs.layout_A) &&
|
||||
(element_B == rhs.element_B) &&
|
||||
(layout_B == rhs.layout_B) &&
|
||||
(element_C == rhs.element_C) &&
|
||||
(layout_C == rhs.layout_C) &&
|
||||
(element_accumulator == rhs.element_accumulator) &&
|
||||
(element_compute == rhs.element_compute);
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator!=(ConvFunctionalKey const &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
inline
|
||||
std::ostream& operator<< (std::ostream& out, const cutlass::library::ConvFunctionalKey& key) {
|
||||
out << "{\n"
|
||||
<< "provider: " << to_string(key.provider) << std::endl
|
||||
<< "conv_kind: " << to_string(key.conv_kind) << std::endl
|
||||
<< "element_A: " << to_string(key.element_A) << std::endl
|
||||
<< "layout_A: " << to_string(key.layout_A) << std::endl
|
||||
<< "element_B: " << to_string(key.element_B) << std::endl
|
||||
<< "layout_B: " << to_string(key.layout_B) << std::endl
|
||||
<< "element_C: " << to_string(key.element_C) << std::endl
|
||||
<< "layout_C: " << to_string(key.layout_C) << std::endl
|
||||
<< "element_accumulator: " << to_string(key.element_accumulator) << std::endl
|
||||
<< "element_compute: " << to_string(key.element_compute) << std::endl
|
||||
<< "}";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
struct ConvFunctionalKeyHasher {
|
||||
using IntHash = std::hash<int>;
|
||||
|
||||
inline
|
||||
static size_t rotl(size_t key, int shl) {
|
||||
return (key << shl) | (key >> (sizeof(key)*8 - shl));
|
||||
}
|
||||
|
||||
inline
|
||||
size_t operator()(ConvFunctionalKey const &key) const {
|
||||
IntHash hash;
|
||||
|
||||
return
|
||||
rotl(hash(int(key.provider)), 1) ^
|
||||
rotl(hash(int(key.conv_kind)), 2) ^
|
||||
rotl(hash(int(key.element_A)), 3) ^
|
||||
rotl(hash(int(key.layout_A)), 4) ^
|
||||
rotl(hash(int(key.element_B)), 5) ^
|
||||
rotl(hash(int(key.layout_B)), 6) ^
|
||||
rotl(hash(int(key.element_C)), 7) ^
|
||||
rotl(hash(int(key.layout_C)), 8) ^
|
||||
rotl(hash(int(key.element_accumulator)), 9) ^
|
||||
rotl(hash(int(key.element_compute)), 10);
|
||||
}
|
||||
};
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Establishes a partial ordering to search for Conv2d operators
|
||||
struct ConvPreferenceKey {
|
||||
|
||||
int compute_capability;
|
||||
IteratorAlgorithmID iterator_algorithm;
|
||||
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
ConvPreferenceKey(): compute_capability(), iterator_algorithm() { }
|
||||
|
||||
ConvPreferenceKey(int cc, IteratorAlgorithmID iterator_algorithm):
|
||||
compute_capability(cc), iterator_algorithm(iterator_algorithm) { }
|
||||
|
||||
bool operator<(ConvPreferenceKey const &rhs) const {
|
||||
return (compute_capability < rhs.compute_capability) ||
|
||||
((compute_capability == rhs.compute_capability) && (iterator_algorithm < rhs.iterator_algorithm));
|
||||
}
|
||||
|
||||
bool operator==(ConvPreferenceKey const &rhs) const {
|
||||
return (compute_capability == rhs.compute_capability) &&
|
||||
(iterator_algorithm == rhs.iterator_algorithm);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Maps minimum compute capability onto a vector of possible operations
|
||||
using ConvOperationVectorMap = std::map<
|
||||
ConvPreferenceKey,
|
||||
std::vector<Operation const *>
|
||||
>;
|
||||
|
||||
/// Maps a GemmFunctionalKey onto a vector of Operation * objects expected to be of kind kGemm
|
||||
using ConvOperationFunctionalMap = std::unordered_map<
|
||||
ConvFunctionalKey,
|
||||
ConvOperationVectorMap,
|
||||
ConvFunctionalKeyHasher
|
||||
>;
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/// Tuple uniquely identifying conv2d functional behavior
|
||||
struct ReductionFunctionalKey {
|
||||
library::Provider provider;
|
||||
library::NumericTypeID element_workspace;
|
||||
library::NumericTypeID element_accumulator;
|
||||
library::NumericTypeID element_output;
|
||||
library::NumericTypeID element_compute;
|
||||
library::MathOperationID reduce_math_op;
|
||||
library::EpilogueKind epilogue_math_op;
|
||||
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
inline
|
||||
ReductionFunctionalKey(
|
||||
library::Provider provider = library::Provider::kInvalid,
|
||||
library::NumericTypeID element_workspace = library::NumericTypeID::kF16,
|
||||
library::NumericTypeID element_accumulator = library::NumericTypeID::kF32,
|
||||
library::NumericTypeID element_output = library::NumericTypeID::kF16,
|
||||
library::NumericTypeID element_compute = library::NumericTypeID::kF32,
|
||||
library::MathOperationID reduce_math_op = library::MathOperationID::kAdd,
|
||||
library::EpilogueKind epilogue_math_op = library::EpilogueKind::kLinearCombination
|
||||
):
|
||||
provider(provider),
|
||||
element_workspace(element_workspace),
|
||||
element_accumulator(element_accumulator),
|
||||
element_output(element_output),
|
||||
element_compute(element_compute),
|
||||
reduce_math_op(reduce_math_op),
|
||||
epilogue_math_op(epilogue_math_op)
|
||||
{ }
|
||||
|
||||
inline
|
||||
bool operator==(ReductionFunctionalKey const &rhs) const {
|
||||
return
|
||||
(provider == rhs.provider) &&
|
||||
(element_workspace == rhs.element_workspace) &&
|
||||
(element_accumulator == rhs.element_accumulator) &&
|
||||
(element_output == rhs.element_output) &&
|
||||
(element_compute == rhs.element_compute) &&
|
||||
(reduce_math_op == rhs.reduce_math_op) &&
|
||||
(epilogue_math_op == rhs.epilogue_math_op);
|
||||
}
|
||||
|
||||
inline
|
||||
bool operator!=(ReductionFunctionalKey const &rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct ReductionFunctionalKeyHasher {
|
||||
using IntHash = std::hash<int>;
|
||||
|
||||
inline
|
||||
static size_t rotl(size_t key, int shl) {
|
||||
return (key << shl) | (key >> (sizeof(key)*8 - shl));
|
||||
}
|
||||
|
||||
inline
|
||||
size_t operator()(ReductionFunctionalKey const &key) const {
|
||||
IntHash hash;
|
||||
|
||||
return
|
||||
rotl(hash(int(key.provider)), 1) ^
|
||||
rotl(hash(int(key.element_workspace)), 2) ^
|
||||
rotl(hash(int(key.element_accumulator)), 3) ^
|
||||
rotl(hash(int(key.element_output)), 4) ^
|
||||
rotl(hash(int(key.element_compute)), 5) ^
|
||||
rotl(hash(int(key.reduce_math_op)), 6) ^
|
||||
rotl(hash(int(key.epilogue_math_op)), 7);
|
||||
}
|
||||
};
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline
|
||||
std::ostream& operator<< (std::ostream& out, const ReductionFunctionalKey& key) {
|
||||
out << "{\n"
|
||||
<< "provider: " << library::to_string(key.provider) << std::endl
|
||||
<< "element_workspace : " << library::to_string(key.element_workspace) << std::endl
|
||||
<< "element_accumulator : " << library::to_string(key.element_accumulator) << std::endl
|
||||
<< "element_output : " << library::to_string(key.element_output) << std::endl
|
||||
<< "element_compute : " << library::to_string(key.element_compute) << std::endl
|
||||
<< "}";
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ReductionOperationFunctionalMap has NO preference key and a single instance per functional key
|
||||
// i.e. only one tile size configuration per functional key
|
||||
using ReductionOperationFunctionalMap = std::unordered_map<
|
||||
ReductionFunctionalKey,
|
||||
library::Operation const *,
|
||||
ReductionFunctionalKeyHasher
|
||||
>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Table of cutlass::library::Operation instances
|
||||
@@ -218,6 +474,18 @@ public:
|
||||
// provider (kCUTLASS)
|
||||
GemmOperationFunctionalMap gemm_operations;
|
||||
|
||||
/// Map of all operations of type kConv2d
|
||||
// provider (kCUTLASS, kReferenceHost, kReferenceDevice)
|
||||
ConvOperationFunctionalMap conv2d_operations;
|
||||
|
||||
/// Map of all operations of type kConv3d
|
||||
// provider (kCUTLASS, kReferenceHost, kReferenceDevice)
|
||||
ConvOperationFunctionalMap conv3d_operations;
|
||||
|
||||
/// Map of all operations of type kConv2d
|
||||
// provider (kCUTLASS)
|
||||
ReductionOperationFunctionalMap reduction_operations;
|
||||
|
||||
public:
|
||||
|
||||
void append(Manifest const &manifest);
|
||||
|
||||
@@ -122,6 +122,27 @@ char const *to_string(SplitKMode split_k_mode, bool pretty = false);
|
||||
template <>
|
||||
SplitKMode from_string<SplitKMode>(std::string const &str);
|
||||
|
||||
/// Converts a ConvModeID enumerant to a string
|
||||
char const *to_string(ConvModeID type, bool pretty = false);
|
||||
|
||||
/// Converts a ConvModeID enumerant from a string
|
||||
template <>
|
||||
ConvModeID from_string<ConvModeID>(std::string const &str);
|
||||
|
||||
/// Converts a IteratorAlgorithmID enumerant to a string
|
||||
char const *to_string(IteratorAlgorithmID type, bool pretty = false);
|
||||
|
||||
/// Converts a IteratorAlgorithmID enumerant from a string
|
||||
template <>
|
||||
IteratorAlgorithmID from_string<IteratorAlgorithmID>(std::string const &str);
|
||||
|
||||
/// Converts a ConvKind enumerant to a string
|
||||
char const *to_string(ConvKind type, bool pretty = false);
|
||||
|
||||
/// Converts a ConvKind enumerant from a string
|
||||
template <>
|
||||
ConvKind from_string<ConvKind>(std::string const &str);
|
||||
|
||||
/// Lexical cast from int64_t to string
|
||||
std::string lexical_cast(int64_t int_value);
|
||||
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
#
|
||||
# \file generator.py
|
||||
#
|
||||
# \brief Generates the CUTLASS Library's instances
|
||||
#
|
||||
#
|
||||
|
||||
import enum
|
||||
import os.path
|
||||
import shutil
|
||||
|
||||
from library import *
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class Conv2dOperation:
|
||||
#
|
||||
def __init__(self, conv_kind, iterator_algorithm, arch, tile_description, A, B, C, element_epilogue, \
|
||||
stride_support, epilogue_functor = EpilogueFunctor.LinearCombination, swizzling_functor = SwizzlingFunctor.Identity4):
|
||||
|
||||
self.operation_kind = OperationKind.Conv2d
|
||||
self.arch = arch
|
||||
self.tile_description = tile_description
|
||||
self.conv_kind = conv_kind
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
self.element_epilogue = element_epilogue
|
||||
self.epilogue_functor = epilogue_functor
|
||||
self.iterator_algorithm = iterator_algorithm
|
||||
self.stride_support = stride_support
|
||||
self.swizzling_functor = swizzling_functor
|
||||
#
|
||||
def is_complex(self):
|
||||
complex_operators = [
|
||||
MathOperation.multiply_add_complex,
|
||||
MathOperation.multiply_add_complex_gaussian
|
||||
]
|
||||
return self.tile_description.math_instruction.math_operation in complex_operators
|
||||
|
||||
#
|
||||
def accumulator_type(self):
|
||||
accum = self.tile_description.math_instruction.element_accumulator
|
||||
|
||||
if self.is_complex():
|
||||
return get_complex_from_real(accum)
|
||||
|
||||
return accum
|
||||
|
||||
#
|
||||
def core_name(self):
|
||||
''' The basic operation kind is prefixed with a letter indicating the accumulation type. '''
|
||||
|
||||
intermediate_type = ''
|
||||
|
||||
if self.tile_description.math_instruction.opcode_class == OpcodeClass.TensorOp:
|
||||
inst_shape = "%d%d%d" % tuple(self.tile_description.math_instruction.instruction_shape)
|
||||
if self.tile_description.math_instruction.element_a != self.A.element and \
|
||||
self.tile_description.math_instruction.element_a != self.accumulator_type():
|
||||
intermediate_type = DataTypeNames[self.tile_description.math_instruction.element_a]
|
||||
else:
|
||||
inst_shape = ''
|
||||
|
||||
return "%s%s%s%s_%s" % (ShortDataTypeNames[self.accumulator_type()], \
|
||||
inst_shape, intermediate_type, ConvKindNames[self.conv_kind], IteratorAlgorithmNames[self.iterator_algorithm])
|
||||
|
||||
#
|
||||
def extended_name(self):
|
||||
''' Append data types if they differ from compute type. '''
|
||||
if self.C.element != self.tile_description.math_instruction.element_accumulator and \
|
||||
self.A.element != self.tile_description.math_instruction.element_accumulator:
|
||||
extended_name = "${element_c}_${core_name}_${element_a}"
|
||||
elif self.C.element == self.tile_description.math_instruction.element_accumulator and \
|
||||
self.A.element != self.tile_description.math_instruction.element_accumulator:
|
||||
extended_name = "${core_name}_${element_a}"
|
||||
else:
|
||||
extended_name = "${core_name}"
|
||||
|
||||
extended_name = SubstituteTemplate(extended_name, {
|
||||
'element_a': DataTypeNames[self.A.element],
|
||||
'element_c': DataTypeNames[self.C.element],
|
||||
'core_name': self.core_name()
|
||||
})
|
||||
|
||||
return extended_name
|
||||
|
||||
#
|
||||
def layout_name(self):
|
||||
return "%s" % (ShortLayoutTypeNames[self.A.layout])
|
||||
|
||||
#
|
||||
def configuration_name(self):
|
||||
''' The full procedural name indicates architecture, extended name, tile size, and layout. '''
|
||||
|
||||
opcode_class_name = OpcodeClassNames[self.tile_description.math_instruction.opcode_class]
|
||||
|
||||
threadblock = "%dx%d_%dx%d" % (
|
||||
self.tile_description.threadblock_shape[0],
|
||||
self.tile_description.threadblock_shape[1],
|
||||
self.tile_description.threadblock_shape[2],
|
||||
self.tile_description.stages
|
||||
)
|
||||
|
||||
if self.stride_support == StrideSupport.Unity:
|
||||
configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}_${layout}_unity_stride"
|
||||
else:
|
||||
configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}_${layout}"
|
||||
|
||||
return SubstituteTemplate(
|
||||
configuration_name,
|
||||
{
|
||||
'opcode_class': opcode_class_name,
|
||||
'extended_name': self.extended_name(),
|
||||
'threadblock': threadblock,
|
||||
'layout': self.layout_name(),
|
||||
}
|
||||
)
|
||||
|
||||
#
|
||||
def procedural_name(self):
|
||||
''' The full procedural name indicates architecture, extended name, tile size, and layout. '''
|
||||
return self.configuration_name()
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Emits single instances of a CUTLASS device-wide operator
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
class EmitConv2dInstance:
|
||||
def __init__(self):
|
||||
self.template = """
|
||||
// Conv2d${conv_kind_name} ${iterator_algorithm_name} kernel instance "${operation_name}"
|
||||
using ${operation_name}_base =
|
||||
typename cutlass::conv::kernel::DefaultConv2d${conv_kind_name}<
|
||||
${element_a},
|
||||
${layout_a},
|
||||
${element_b},
|
||||
${layout_b},
|
||||
${element_c},
|
||||
${layout_c},
|
||||
${element_accumulator},
|
||||
${opcode_class},
|
||||
${arch},
|
||||
cutlass::gemm::GemmShape<${threadblock_shape_m}, ${threadblock_shape_n}, ${threadblock_shape_k}>,
|
||||
cutlass::gemm::GemmShape<${warp_shape_m}, ${warp_shape_n}, ${warp_shape_k} >,
|
||||
cutlass::gemm::GemmShape<${instruction_shape_m}, ${instruction_shape_n}, ${instruction_shape_k}>,
|
||||
${epilogue_functor}<
|
||||
${element_c},
|
||||
${epilogue_vector_length},
|
||||
${element_accumulator},
|
||||
${element_epilogue}
|
||||
>,
|
||||
${swizzling_functor}, // cutlass::gemm::threadblock::GemmSplitKIdentityThreadblockSwizzle<>,
|
||||
${stages},
|
||||
${math_operator},
|
||||
${iterator_algorithm},
|
||||
${stride_support}
|
||||
>::Kernel;
|
||||
"""
|
||||
|
||||
|
||||
def emit(self, operation):
|
||||
|
||||
warp_shape = [int(operation.tile_description.threadblock_shape[idx] / operation.tile_description.warp_count[idx]) for idx in range(3)]
|
||||
|
||||
epilogue_vector_length = int(min(operation.C.alignment * DataTypeSize[operation.C.element], 128) / DataTypeSize[operation.C.element])
|
||||
|
||||
values = {
|
||||
'operation_name': operation.procedural_name(),
|
||||
'conv_kind': ConvKindTag[operation.conv_kind],
|
||||
'conv_kind_name': ConvKindNames[operation.conv_kind].capitalize(),
|
||||
'element_a': DataTypeTag[operation.A.element],
|
||||
'layout_a': LayoutTag[operation.A.layout],
|
||||
'element_b': DataTypeTag[operation.B.element],
|
||||
'layout_b': LayoutTag[operation.B.layout],
|
||||
'element_c': DataTypeTag[operation.C.element],
|
||||
'layout_c': LayoutTag[operation.C.layout],
|
||||
'element_accumulator': DataTypeTag[operation.accumulator_type()],
|
||||
'opcode_class': OpcodeClassTag[operation.tile_description.math_instruction.opcode_class],
|
||||
'arch': "cutlass::arch::Sm%d" % operation.arch,
|
||||
'threadblock_shape_m': str(operation.tile_description.threadblock_shape[0]),
|
||||
'threadblock_shape_n': str(operation.tile_description.threadblock_shape[1]),
|
||||
'threadblock_shape_k': str(operation.tile_description.threadblock_shape[2]),
|
||||
'warp_shape_m': str(warp_shape[0]),
|
||||
'warp_shape_n': str(warp_shape[1]),
|
||||
'warp_shape_k': str(warp_shape[2]),
|
||||
'instruction_shape_m': str(operation.tile_description.math_instruction.instruction_shape[0]),
|
||||
'instruction_shape_n': str(operation.tile_description.math_instruction.instruction_shape[1]),
|
||||
'instruction_shape_k': str(operation.tile_description.math_instruction.instruction_shape[2]),
|
||||
'epilogue_vector_length': str(epilogue_vector_length),
|
||||
'epilogue_functor': EpilogueFunctorTag[operation.epilogue_functor],
|
||||
'element_epilogue': str(DataTypeTag[operation.element_epilogue]),
|
||||
'swizzling_functor': SwizzlingFunctorTag[operation.swizzling_functor],
|
||||
'stages': str(operation.tile_description.stages),
|
||||
'iterator_algorithm': IteratorAlgorithmTag[operation.iterator_algorithm],
|
||||
'iterator_algorithm_name': IteratorAlgorithmNames[operation.iterator_algorithm].capitalize(),
|
||||
'stride_support': StrideSupportTag[operation.stride_support],
|
||||
'math_operator': 'cutlass::arch::OpMultiplyAddComplex' if operation.is_complex() else \
|
||||
MathOperationTag[operation.tile_description.math_instruction.math_operation]
|
||||
}
|
||||
|
||||
return SubstituteTemplate(self.template, values)
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Generator functions for all layouts
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
def GenerateConv2dTensorOp(manifest, tile_descriptions, min_cc, align = 128):
|
||||
|
||||
for tile in tile_descriptions:
|
||||
for conv_kind in [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad]:
|
||||
|
||||
if conv_kind == ConvKind.Fprop or (tile.math_instruction.element_accumulator in [DataType.f16, DataType.f32]):
|
||||
|
||||
#
|
||||
output_types = [tile.math_instruction.element_a, tile.math_instruction.element_accumulator] \
|
||||
if DataTypeSize[tile.math_instruction.element_accumulator] == 32 \
|
||||
else [tile.math_instruction.element_accumulator,]
|
||||
|
||||
for output_type in output_types:
|
||||
A = TensorDescription(tile.math_instruction.element_a, LayoutType.TensorNHWC, int(align / DataTypeSize[tile.math_instruction.element_a]))
|
||||
B = TensorDescription(tile.math_instruction.element_b, LayoutType.TensorNHWC, int(align / DataTypeSize[tile.math_instruction.element_b]))
|
||||
C = TensorDescription(output_type, LayoutType.TensorNHWC, max(1, int(align / DataTypeSize[output_type])))
|
||||
|
||||
manifest.append(Conv2dOperation(conv_kind, min_cc, tile, A, B, C, tile.math_instruction.element_accumulator))
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Emitters functions for all targets
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
class EmitConv2dConfigurationLibrary:
|
||||
def __init__(self, operation_path, configuration_name):
|
||||
self.configuration_name = configuration_name
|
||||
self.configuration_path = os.path.join(operation_path, "%s.cu" % configuration_name)
|
||||
|
||||
self.instance_emitter = EmitConv2dInstance()
|
||||
|
||||
self.instance_template = """
|
||||
${operation_instance}
|
||||
|
||||
// Derived class
|
||||
struct ${operation_name} :
|
||||
public ${operation_name}_base { };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
"""
|
||||
self.header_template = """
|
||||
/*
|
||||
Generated by conv2d_operation.py - Do not edit.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
#include "library_internal.h"
|
||||
#include "conv2d_operation.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
"""
|
||||
|
||||
self.configuration_header = """
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
// Initialize all instances
|
||||
void initialize_${configuration_name}(Manifest &manifest) {
|
||||
|
||||
"""
|
||||
|
||||
self.configuration_instance = """
|
||||
using Operation_${operation_name} = cutlass::conv::device::ImplicitGemmConvolution<
|
||||
${operation_name}>;
|
||||
|
||||
manifest.append(new cutlass::library::Conv2dOperation<
|
||||
Operation_${operation_name}>(
|
||||
"${operation_name}"));
|
||||
|
||||
"""
|
||||
|
||||
self.configuration_epilogue = """
|
||||
}
|
||||
"""
|
||||
self.epilogue_template = """
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
def __enter__(self):
|
||||
self.configuration_file = open(self.configuration_path, "w")
|
||||
self.configuration_file.write(SubstituteTemplate(self.header_template, {
|
||||
'configuration_name': self.configuration_name
|
||||
}))
|
||||
self.operations = []
|
||||
return self
|
||||
|
||||
#
|
||||
def emit(self, operation):
|
||||
self.operations.append(operation)
|
||||
self.configuration_file.write(SubstituteTemplate(self.instance_template, {
|
||||
'configuration_name': self.configuration_name,
|
||||
'operation_name': operation.procedural_name(),
|
||||
'operation_instance': self.instance_emitter.emit(operation)
|
||||
}))
|
||||
|
||||
#
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
|
||||
self.configuration_file.write(SubstituteTemplate(self.configuration_header, {
|
||||
'configuration_name': self.configuration_name
|
||||
}))
|
||||
|
||||
for operation in self.operations:
|
||||
self.configuration_file.write(SubstituteTemplate(self.configuration_instance, {
|
||||
'configuration_name': self.configuration_name,
|
||||
'operation_name': operation.procedural_name()
|
||||
}))
|
||||
|
||||
self.configuration_file.write(self.configuration_epilogue)
|
||||
self.configuration_file.write(self.epilogue_template)
|
||||
self.configuration_file.close()
|
||||
|
||||
|
||||
###################################################################################################
|
||||
###################################################################################################
|
||||
|
||||
@@ -0,0 +1,321 @@
|
||||
#
|
||||
# \file generator.py
|
||||
#
|
||||
# \brief Generates the CUTLASS Library's instances
|
||||
#
|
||||
#
|
||||
|
||||
import enum
|
||||
import os.path
|
||||
import shutil
|
||||
|
||||
from library import *
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class Conv3dOperation:
|
||||
#
|
||||
def __init__(self, conv_kind, iterator_algorithm, arch, tile_description, A, B, C, element_epilogue, \
|
||||
stride_support, epilogue_functor = EpilogueFunctor.LinearCombination, swizzling_functor = SwizzlingFunctor.Identity4):
|
||||
|
||||
self.operation_kind = OperationKind.Conv3d
|
||||
self.arch = arch
|
||||
self.tile_description = tile_description
|
||||
self.conv_kind = conv_kind
|
||||
self.A = A
|
||||
self.B = B
|
||||
self.C = C
|
||||
self.element_epilogue = element_epilogue
|
||||
self.epilogue_functor = epilogue_functor
|
||||
self.iterator_algorithm = iterator_algorithm
|
||||
self.stride_support = stride_support
|
||||
self.swizzling_functor = swizzling_functor
|
||||
|
||||
#
|
||||
def core_name(self):
|
||||
''' The basic operation kind is prefixed with a letter indicating the accumulation type. '''
|
||||
|
||||
intermediate_type = ''
|
||||
|
||||
if self.tile_description.math_instruction.opcode_class == OpcodeClass.TensorOp:
|
||||
inst_shape = "%d%d%d" % tuple(self.tile_description.math_instruction.instruction_shape)
|
||||
if self.tile_description.math_instruction.element_a != self.A.element and \
|
||||
self.tile_description.math_instruction.element_a != self.tile_description.math_instruction.element_accumulator:
|
||||
intermediate_type = DataTypeNames[self.tile_description.math_instruction.element_a]
|
||||
else:
|
||||
inst_shape = ''
|
||||
|
||||
return "%s%s%s%s3d_%s" % (ShortDataTypeNames[self.tile_description.math_instruction.element_accumulator], \
|
||||
inst_shape, intermediate_type, ConvKindNames[self.conv_kind], IteratorAlgorithmNames[self.iterator_algorithm])
|
||||
|
||||
#
|
||||
def extended_name(self):
|
||||
''' Append data types if they differ from compute type. '''
|
||||
if self.C.element != self.tile_description.math_instruction.element_accumulator and \
|
||||
self.A.element != self.tile_description.math_instruction.element_accumulator:
|
||||
extended_name = "${element_c}_${core_name}_${element_a}"
|
||||
elif self.C.element == self.tile_description.math_instruction.element_accumulator and \
|
||||
self.A.element != self.tile_description.math_instruction.element_accumulator:
|
||||
extended_name = "${core_name}_${element_a}"
|
||||
else:
|
||||
extended_name = "${core_name}"
|
||||
|
||||
extended_name = SubstituteTemplate(extended_name, {
|
||||
'element_a': DataTypeNames[self.A.element],
|
||||
'element_c': DataTypeNames[self.C.element],
|
||||
'core_name': self.core_name()
|
||||
})
|
||||
|
||||
return extended_name
|
||||
|
||||
#
|
||||
def configuration_name(self):
|
||||
''' The full procedural name indicates architecture, extended name, tile size, and layout. '''
|
||||
|
||||
opcode_class_name = OpcodeClassNames[self.tile_description.math_instruction.opcode_class]
|
||||
|
||||
threadblock = "%dx%d_%dx%d" % (
|
||||
self.tile_description.threadblock_shape[0],
|
||||
self.tile_description.threadblock_shape[1],
|
||||
self.tile_description.threadblock_shape[2],
|
||||
self.tile_description.stages
|
||||
)
|
||||
|
||||
if self.stride_support == StrideSupport.Unity:
|
||||
configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}_unity_stride"
|
||||
else:
|
||||
configuration_name = "cutlass_${opcode_class}_${extended_name}_${threadblock}"
|
||||
|
||||
return SubstituteTemplate(
|
||||
configuration_name,
|
||||
{
|
||||
'opcode_class': opcode_class_name,
|
||||
'extended_name': self.extended_name(),
|
||||
'threadblock': threadblock,
|
||||
}
|
||||
)
|
||||
|
||||
#
|
||||
def procedural_name(self):
|
||||
''' The full procedural name indicates architecture, extended name, tile size, and layout. '''
|
||||
return self.configuration_name()
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Emits single instances of a CUTLASS device-wide operator
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
class EmitConv3dInstance:
|
||||
def __init__(self):
|
||||
self.template = """
|
||||
// Conv3d${conv_kind_name} ${iterator_algorithm_name} kernel instance "${operation_name}"
|
||||
using ${operation_name}_base =
|
||||
typename cutlass::conv::kernel::DefaultConv3d${conv_kind_name}<
|
||||
${element_a},
|
||||
cutlass::layout::TensorNDHWC,
|
||||
${element_b},
|
||||
cutlass::layout::TensorNDHWC,
|
||||
${element_c},
|
||||
cutlass::layout::TensorNDHWC,
|
||||
${element_accumulator},
|
||||
${opcode_class},
|
||||
${arch},
|
||||
cutlass::gemm::GemmShape<${threadblock_shape_m}, ${threadblock_shape_n}, ${threadblock_shape_k}>,
|
||||
cutlass::gemm::GemmShape<${warp_shape_m}, ${warp_shape_n}, ${warp_shape_k} >,
|
||||
cutlass::gemm::GemmShape<${instruction_shape_m}, ${instruction_shape_n}, ${instruction_shape_k}>,
|
||||
${epilogue_functor}<
|
||||
${element_c},
|
||||
${epilogue_vector_length},
|
||||
${element_accumulator},
|
||||
${element_epilogue}
|
||||
>,
|
||||
${swizzling_functor}, // cutlass::gemm::threadblock::GemmSplitKIdentityThreadblockSwizzle<>,
|
||||
${stages},
|
||||
cutlass::arch::OpMultiplyAdd,
|
||||
${iterator_algorithm},
|
||||
${stride_support}
|
||||
>::Kernel;
|
||||
"""
|
||||
|
||||
|
||||
def emit(self, operation):
|
||||
|
||||
warp_shape = [int(operation.tile_description.threadblock_shape[idx] / operation.tile_description.warp_count[idx]) for idx in range(3)]
|
||||
|
||||
epilogue_vector_length = int(min(operation.C.alignment * DataTypeSize[operation.C.element], 128) / DataTypeSize[operation.C.element])
|
||||
|
||||
values = {
|
||||
'operation_name': operation.procedural_name(),
|
||||
'conv_kind': ConvKindTag[operation.conv_kind],
|
||||
'conv_kind_name': ConvKindNames[operation.conv_kind].capitalize(),
|
||||
'element_a': DataTypeTag[operation.A.element],
|
||||
'layout_a': LayoutTag[operation.A.layout],
|
||||
'element_b': DataTypeTag[operation.B.element],
|
||||
'layout_b': LayoutTag[operation.B.layout],
|
||||
'element_c': DataTypeTag[operation.C.element],
|
||||
'layout_c': LayoutTag[operation.C.layout],
|
||||
'element_accumulator': DataTypeTag[operation.tile_description.math_instruction.element_accumulator],
|
||||
'opcode_class': OpcodeClassTag[operation.tile_description.math_instruction.opcode_class],
|
||||
'arch': "cutlass::arch::Sm%d" % operation.arch,
|
||||
'threadblock_shape_m': str(operation.tile_description.threadblock_shape[0]),
|
||||
'threadblock_shape_n': str(operation.tile_description.threadblock_shape[1]),
|
||||
'threadblock_shape_k': str(operation.tile_description.threadblock_shape[2]),
|
||||
'warp_shape_m': str(warp_shape[0]),
|
||||
'warp_shape_n': str(warp_shape[1]),
|
||||
'warp_shape_k': str(warp_shape[2]),
|
||||
'instruction_shape_m': str(operation.tile_description.math_instruction.instruction_shape[0]),
|
||||
'instruction_shape_n': str(operation.tile_description.math_instruction.instruction_shape[1]),
|
||||
'instruction_shape_k': str(operation.tile_description.math_instruction.instruction_shape[2]),
|
||||
'epilogue_vector_length': str(epilogue_vector_length),
|
||||
'epilogue_functor': EpilogueFunctorTag[operation.epilogue_functor],
|
||||
'element_epilogue': str(DataTypeTag[operation.element_epilogue]),
|
||||
'swizzling_functor': SwizzlingFunctorTag[operation.swizzling_functor],
|
||||
'stages': str(operation.tile_description.stages),
|
||||
'iterator_algorithm': IteratorAlgorithmTag[operation.iterator_algorithm],
|
||||
'iterator_algorithm_name': IteratorAlgorithmNames[operation.iterator_algorithm].capitalize(),
|
||||
'stride_support': StrideSupportTag[operation.stride_support]
|
||||
}
|
||||
|
||||
return SubstituteTemplate(self.template, values)
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Generator functions for all layouts
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
def GenerateConv3dTensorOp(manifest, tile_descriptions, min_cc, align = 128):
|
||||
|
||||
for tile in tile_descriptions:
|
||||
for conv_kind in [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad]:
|
||||
|
||||
if conv_kind == ConvKind.Fprop or (tile.math_instruction.element_accumulator in [DataType.f16, DataType.f32]):
|
||||
|
||||
#
|
||||
output_types = [tile.math_instruction.element_a, tile.math_instruction.element_accumulator] \
|
||||
if DataTypeSize[tile.math_instruction.element_accumulator] == 32 \
|
||||
else [tile.math_instruction.element_accumulator,]
|
||||
|
||||
for output_type in output_types:
|
||||
A = TensorDescription(tile.math_instruction.element_a, LayoutType.TensorNDHWC, int(align / DataTypeSize[tile.math_instruction.element_a]))
|
||||
B = TensorDescription(tile.math_instruction.element_b, LayoutType.TensorNDHWC, int(align / DataTypeSize[tile.math_instruction.element_b]))
|
||||
C = TensorDescription(output_type, LayoutType.TensorNDHWC, max(1, int(align / DataTypeSize[output_type])))
|
||||
|
||||
manifest.append(Conv3dOperation(conv_kind, min_cc, tile, A, B, C, tile.math_instruction.element_accumulator))
|
||||
|
||||
###################################################################################################
|
||||
#
|
||||
# Emitters functions for all targets
|
||||
#
|
||||
###################################################################################################
|
||||
|
||||
class EmitConv3dConfigurationLibrary:
|
||||
def __init__(self, operation_path, configuration_name):
|
||||
self.configuration_name = configuration_name
|
||||
self.configuration_path = os.path.join(operation_path, "%s.cu" % configuration_name)
|
||||
|
||||
self.instance_emitter = EmitConv3dInstance()
|
||||
|
||||
self.instance_template = """
|
||||
${operation_instance}
|
||||
|
||||
// Derived class
|
||||
struct ${operation_name} :
|
||||
public ${operation_name}_base { };
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
"""
|
||||
self.header_template = """
|
||||
/*
|
||||
Generated by conv3d_operation.py - Do not edit.
|
||||
*/
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
#include "library_internal.h"
|
||||
#include "conv3d_operation.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
"""
|
||||
|
||||
self.configuration_header = """
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
// Initialize all instances
|
||||
void initialize_${configuration_name}(Manifest &manifest) {
|
||||
|
||||
"""
|
||||
|
||||
self.configuration_instance = """
|
||||
using Operation_${operation_name} = cutlass::conv::device::ImplicitGemmConvolution<
|
||||
${operation_name}>;
|
||||
|
||||
manifest.append(new cutlass::library::Conv3dOperation<
|
||||
Operation_${operation_name}>(
|
||||
"${operation_name}"));
|
||||
|
||||
"""
|
||||
|
||||
self.configuration_epilogue = """
|
||||
}
|
||||
"""
|
||||
self.epilogue_template = """
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
"""
|
||||
|
||||
#
|
||||
def __enter__(self):
|
||||
self.configuration_file = open(self.configuration_path, "w")
|
||||
self.configuration_file.write(SubstituteTemplate(self.header_template, {
|
||||
'configuration_name': self.configuration_name
|
||||
}))
|
||||
self.operations = []
|
||||
return self
|
||||
|
||||
#
|
||||
def emit(self, operation):
|
||||
self.operations.append(operation)
|
||||
self.configuration_file.write(SubstituteTemplate(self.instance_template, {
|
||||
'configuration_name': self.configuration_name,
|
||||
'operation_name': operation.procedural_name(),
|
||||
'operation_instance': self.instance_emitter.emit(operation)
|
||||
}))
|
||||
|
||||
#
|
||||
def __exit__(self, exception_type, exception_value, traceback):
|
||||
|
||||
self.configuration_file.write(SubstituteTemplate(self.configuration_header, {
|
||||
'configuration_name': self.configuration_name
|
||||
}))
|
||||
|
||||
for operation in self.operations:
|
||||
self.configuration_file.write(SubstituteTemplate(self.configuration_instance, {
|
||||
'configuration_name': self.configuration_name,
|
||||
'operation_name': operation.procedural_name()
|
||||
}))
|
||||
|
||||
self.configuration_file.write(self.configuration_epilogue)
|
||||
self.configuration_file.write(self.epilogue_template)
|
||||
self.configuration_file.close()
|
||||
|
||||
|
||||
###################################################################################################
|
||||
###################################################################################################
|
||||
|
||||
+360
-126
@@ -11,7 +11,6 @@ import argparse
|
||||
|
||||
from library import *
|
||||
from manifest import *
|
||||
from gemm_operation import *
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
@@ -118,10 +117,9 @@ def CreateGemmPlanarComplexOperator(manifest, layouts, tile_descriptions, data_t
|
||||
|
||||
gemm_kinds = [GemmKind.PlanarComplex, GemmKind.PlanarComplexArray]
|
||||
|
||||
# by default, only generate the largest tile and largest alignment
|
||||
# by default, planar complex gemm kernels are not generated
|
||||
if manifest.args.kernels == '':
|
||||
tile_descriptions = [tile_descriptions[0],]
|
||||
alignment_constraints = [alignment_constraints[0],]
|
||||
return
|
||||
|
||||
for gemm_kind in gemm_kinds:
|
||||
for layout in layouts:
|
||||
@@ -141,6 +139,103 @@ def CreateGemmPlanarComplexOperator(manifest, layouts, tile_descriptions, data_t
|
||||
return
|
||||
|
||||
###########################################################################################################
|
||||
# ConvolutionOperator support variations
|
||||
# ____________________________________________________________________
|
||||
# ConvolutionalOperator | Analytic | Optimized
|
||||
# ____________________________________________________________________
|
||||
# | Fprop | (strided) | (strided)
|
||||
# | Dgrad | (strided, unity*) | (unity)
|
||||
# | Wgrad | (strided) | (strided)
|
||||
# ____________________________________________________________________
|
||||
#
|
||||
# Note : Operator marked (*) are supported but not generated to keep the instantiated kernel count low
|
||||
###########################################################################################################
|
||||
# Convolution for 2D operations
|
||||
def CreateConv2dOperator(manifest, layout, tile_descriptions, data_type, alignment, \
|
||||
conv_kinds = [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad], epilogue_functor = EpilogueFunctor.LinearCombination):
|
||||
|
||||
element_a, element_b, element_c, element_epilogue = data_type
|
||||
|
||||
# one exceptional case
|
||||
alignment_c = min(8, alignment)
|
||||
|
||||
# iterator algorithm (analytic and optimized)
|
||||
iterator_algorithms = [IteratorAlgorithm.Analytic, IteratorAlgorithm.Optimized]
|
||||
|
||||
# by default, only generate the largest tile size
|
||||
if manifest.args.kernels == '':
|
||||
tile_descriptions = [tile_descriptions[0],]
|
||||
|
||||
operations = []
|
||||
|
||||
for tile in tile_descriptions:
|
||||
for conv_kind in conv_kinds:
|
||||
for iterator_algorithm in iterator_algorithms:
|
||||
A = TensorDescription(element_a, layout[0], alignment)
|
||||
B = TensorDescription(element_b, layout[1], alignment)
|
||||
C = TensorDescription(element_c, layout[2], alignment_c)
|
||||
|
||||
# unity stride only for Optimized Dgrad
|
||||
if (iterator_algorithm == IteratorAlgorithm.Optimized) and (conv_kind == ConvKind.Dgrad):
|
||||
new_operation = Conv2dOperation(conv_kind, iterator_algorithm, tile.minimum_compute_capability, tile,\
|
||||
A, B, C, element_epilogue, StrideSupport.Unity, epilogue_functor)
|
||||
|
||||
manifest.append(new_operation)
|
||||
operations.append(new_operation)
|
||||
|
||||
# strided dgrad is not supported by Optimized Dgrad
|
||||
if (iterator_algorithm == IteratorAlgorithm.Optimized) and (conv_kind == ConvKind.Dgrad):
|
||||
continue
|
||||
|
||||
# strided support for Fprop (Analytic/Optimized), Dgrad (Analytic), and Wgrad (Analytic)
|
||||
new_operation = Conv2dOperation(conv_kind, iterator_algorithm, tile.minimum_compute_capability, tile,\
|
||||
A, B, C, element_epilogue, StrideSupport.Strided, epilogue_functor)
|
||||
|
||||
manifest.append(new_operation)
|
||||
operations.append(new_operation)
|
||||
|
||||
return operations
|
||||
|
||||
# Convolution for 3D operations
|
||||
def CreateConv3dOperator(manifest, layout, tile_descriptions, data_type, alignment, \
|
||||
conv_kinds = [ConvKind.Fprop, ConvKind.Dgrad, ConvKind.Wgrad], epilogue_functor = EpilogueFunctor.LinearCombination):
|
||||
|
||||
element_a, element_b, element_c, element_epilogue = data_type
|
||||
|
||||
# one exceptional case
|
||||
alignment_c = min(8, alignment)
|
||||
|
||||
# iterator algorithm (analytic and optimized)
|
||||
iterator_algorithms = [IteratorAlgorithm.Analytic, IteratorAlgorithm.Optimized]
|
||||
|
||||
# by default, only generate the largest tile size
|
||||
if manifest.args.kernels == '':
|
||||
tile_descriptions = [tile_descriptions[0],]
|
||||
|
||||
operations = []
|
||||
|
||||
for tile in tile_descriptions:
|
||||
for conv_kind in conv_kinds:
|
||||
for iterator_algorithm in iterator_algorithms:
|
||||
A = TensorDescription(element_a, layout, alignment)
|
||||
B = TensorDescription(element_b, layout, alignment)
|
||||
C = TensorDescription(element_c, layout, alignment_c)
|
||||
|
||||
# optimized conv3d iterator algorithm is only for Wgrad
|
||||
if (iterator_algorithm == IteratorAlgorithm.Optimized) \
|
||||
and ((conv_kind == ConvKind.Fprop) or (conv_kind == ConvKind.Dgrad)):
|
||||
continue
|
||||
|
||||
# strided support for Fprop (Analytic/Optimized), Dgrad (Analytic), and Wgrad (Analytic)
|
||||
new_operation = Conv3dOperation(conv_kind, iterator_algorithm, tile.minimum_compute_capability, tile,\
|
||||
A, B, C, element_epilogue, StrideSupport.Strided, epilogue_functor)
|
||||
|
||||
manifest.append(new_operation)
|
||||
operations.append(new_operation)
|
||||
|
||||
|
||||
return operations
|
||||
|
||||
###################################################################################################
|
||||
###################################################################################################
|
||||
|
||||
@@ -191,11 +286,57 @@ def GenerateSM50_Simt(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
if math_inst.element_a == DataType.f32:
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1)
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM50_Simt_complex(manifest, args):
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[1, 1, 1], \
|
||||
DataType.f32, DataType.f32, DataType.f32, \
|
||||
OpcodeClass.Simt, \
|
||||
MathOperation.multiply_add_complex),
|
||||
]
|
||||
|
||||
min_cc = 50
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([128, 128, 8], 2, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
]
|
||||
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1)
|
||||
#
|
||||
|
||||
#
|
||||
def GenerateSM50(manifest, args):
|
||||
GenerateSM50_Simt(manifest, args)
|
||||
GenerateSM50_Simt_complex(manifest, args)
|
||||
|
||||
###################################################################################################
|
||||
###################################################################################################
|
||||
@@ -362,6 +503,9 @@ def GenerateSM70_TensorOp_884(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 8)
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
if math_inst.element_a != math_inst.element_accumulator:
|
||||
|
||||
@@ -375,6 +519,8 @@ def GenerateSM70_TensorOp_884(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints)
|
||||
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 8)
|
||||
|
||||
#
|
||||
def GenerateSM70_PlanarComplexTensorOp_884(manifest, args):
|
||||
|
||||
@@ -504,50 +650,10 @@ def GenerateSM70_WmmaTensorOp_161616(manifest, args):
|
||||
#
|
||||
##################################################################################################
|
||||
#
|
||||
def GenerateSM70_Simt_complex(manifest, args):
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[1, 1, 1], \
|
||||
DataType.f32, DataType.f32, DataType.f32, \
|
||||
OpcodeClass.Simt, \
|
||||
MathOperation.multiply_add_complex),
|
||||
]
|
||||
|
||||
min_cc = 70
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([128, 128, 8], 2, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 2, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 2, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 32, 16], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 64, 16], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 32, 16], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
data_type = [
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32
|
||||
]
|
||||
|
||||
complex_transforms = [
|
||||
(ComplexTransform.none, ComplexTransform.none),
|
||||
(ComplexTransform.conj, ComplexTransform.none),
|
||||
(ComplexTransform.none, ComplexTransform.conj),
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
|
||||
#
|
||||
|
||||
def GenerateSM70(manifest, args):
|
||||
GenerateSM70_TensorOp_884(manifest, args)
|
||||
GenerateSM70_PlanarComplexTensorOp_884(manifest, args)
|
||||
GenerateSM70_Simt_complex(manifest, args)
|
||||
|
||||
# To limit build size, WMMA GEMMs are disabled for now.
|
||||
#
|
||||
@@ -607,6 +713,9 @@ def GenerateSM75_TensorOp_1688(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 8)
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
if math_inst.element_a != math_inst.element_accumulator:
|
||||
|
||||
@@ -620,6 +729,8 @@ def GenerateSM75_TensorOp_1688(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints)
|
||||
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 8)
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
@@ -738,6 +849,10 @@ def GenerateSM75_TensorOp_8816_TN(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
data_type, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
if math_inst.element_a != math_inst.element_accumulator:
|
||||
|
||||
@@ -753,6 +868,9 @@ def GenerateSM75_TensorOp_8816_TN(manifest, args):
|
||||
operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
if op.tile_description.threadblock_shape[1] >= 128:
|
||||
op.C.alignment = 16
|
||||
@@ -794,6 +912,8 @@ def GenerateSM75_TensorOp_8816_Interleaved(manifest, args):
|
||||
TileDescription([256, 128, 64], 2, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 64], 2, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 64], 2, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 64], 2, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
@@ -809,9 +929,13 @@ def GenerateSM75_TensorOp_8816_Interleaved(manifest, args):
|
||||
operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
# conv_layout = (LayoutType.TensorNC32HW32, LayoutType.TensorC32RSK32, LayoutType.TensorNC32HW32)
|
||||
#
|
||||
# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
# data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 8
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
@@ -862,6 +986,10 @@ def GenerateSM75_TensorOp_8832_TN(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
data_type, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
if math_inst.element_a != math_inst.element_accumulator:
|
||||
|
||||
@@ -877,6 +1005,9 @@ def GenerateSM75_TensorOp_8832_TN(manifest, args):
|
||||
operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
data_type_mixed, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
if op.tile_description.threadblock_shape[1] >= 128:
|
||||
op.C.alignment = 8
|
||||
@@ -920,9 +1051,9 @@ def GenerateSM75_TensorOp_8832_Interleaved(manifest, args):
|
||||
TileDescription([256, 128, 128], 2, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 128], 2, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 128], 2, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 128], 2, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 2, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
@@ -938,9 +1069,13 @@ def GenerateSM75_TensorOp_8832_Interleaved(manifest, args):
|
||||
operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
# conv_layout = (LayoutType.TensorNC64HW64, LayoutType.TensorC64RSK64, LayoutType.TensorNC64HW64)
|
||||
#
|
||||
# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
# data_type_mixed, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 16
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
@@ -1074,6 +1209,8 @@ def GenerateSM75_Simt_complex(manifest, args):
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1)
|
||||
#
|
||||
|
||||
def GenerateSM75(manifest, args):
|
||||
@@ -1124,6 +1261,7 @@ def GenerateSM80_TensorOp_16816(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [8, 4, 2]
|
||||
|
||||
@@ -1137,10 +1275,10 @@ def GenerateSM80_TensorOp_16816(manifest, args):
|
||||
TileDescription([128, 64, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 64], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 64], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 64], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 256, 64], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
@@ -1157,6 +1295,10 @@ def GenerateSM80_TensorOp_16816(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 8)
|
||||
CreateConv3dOperator(manifest, LayoutType.TensorNDHWC, tile_descriptions, data_type, 8)
|
||||
|
||||
# Avoid emitting two kernels if the accumulator type does not differ from the input type (e.g. F16 accumulation)
|
||||
if math_inst.element_a != math_inst.element_accumulator:
|
||||
|
||||
@@ -1170,6 +1312,8 @@ def GenerateSM80_TensorOp_16816(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints)
|
||||
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 8)
|
||||
CreateConv3dOperator(manifest, LayoutType.TensorNDHWC, tile_descriptions, data_type_mixed, 8)
|
||||
#
|
||||
|
||||
#
|
||||
@@ -1205,22 +1349,23 @@ def GenerateSM80_SparseTensorOp_16832(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [8, 4, 2]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 64], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 64], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 64], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
@@ -1348,6 +1493,7 @@ def GenerateSM80_TensorOp_16832_TN(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [16,]
|
||||
|
||||
@@ -1361,10 +1507,10 @@ def GenerateSM80_TensorOp_16832_TN(manifest, args):
|
||||
TileDescription([128, 64, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 64], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 128], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 128], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
@@ -1382,6 +1528,13 @@ def GenerateSM80_TensorOp_16832_TN(manifest, args):
|
||||
operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
data_type, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
if op.tile_description.threadblock_shape[1] >= 128:
|
||||
op.C.alignment = 16
|
||||
@@ -1409,21 +1562,22 @@ def GenerateSM80_SparseTensorOp_16864_TN(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [16,]
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 128], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 128], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 128], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 128], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 64, 128], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
@@ -1489,10 +1643,14 @@ def GenerateSM80_TensorOp_16832_Interleaved(manifest, args):
|
||||
|
||||
operations = CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
|
||||
# conv_layout = (LayoutType.TensorNC32HW32, LayoutType.TensorC32RSK32, LayoutType.TensorNC32HW32)
|
||||
#
|
||||
# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
# data_type_mixed, 16, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 8
|
||||
|
||||
#
|
||||
|
||||
#
|
||||
@@ -1520,6 +1678,7 @@ def GenerateSM80_TensorOp_16864_TN(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [32,]
|
||||
|
||||
@@ -1533,14 +1692,14 @@ def GenerateSM80_TensorOp_16864_TN(manifest, args):
|
||||
TileDescription([128, 64, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 256], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 256], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 256], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 256], 5, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
]
|
||||
|
||||
data_type = [math_inst.element_a, math_inst.element_b, math_inst.element_accumulator, DataType.s32]
|
||||
@@ -1582,20 +1741,21 @@ def GenerateSM80_SparseTensorOp_168128_TN(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [32,]
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 256], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 256], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 256], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 512], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 512], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 256], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 256], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 256], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 256, 256], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 256], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 128, 256], 6, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 512], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 512], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 128, 512], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 512], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
@@ -1655,9 +1815,7 @@ def GenerateSM80_TensorOp_16864_Interleaved(manifest, args):
|
||||
TileDescription([256, 64, 128], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 128], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 128], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 128], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 128], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type_mixed = [math_inst.element_a, math_inst.element_b, math_inst.element_a, DataType.f32]
|
||||
@@ -1666,7 +1824,12 @@ def GenerateSM80_TensorOp_16864_Interleaved(manifest, args):
|
||||
|
||||
operations += CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints, None, EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
|
||||
# conv_layout = (LayoutType.TensorNC64HW64, LayoutType.TensorC64RSK64, LayoutType.TensorNC64HW64)
|
||||
#
|
||||
# operations += CreateConv2dOperator(manifest, conv_layout, tile_descriptions,
|
||||
# data_type_mixed, 32, [ConvKind.Fprop], EpilogueFunctor.LinearCombinationClamp)
|
||||
|
||||
for op in operations:
|
||||
op.C.alignment = 16
|
||||
#
|
||||
@@ -1744,6 +1907,7 @@ def GenerateSM80_TensorOp_1688(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [4, 2, 1]
|
||||
|
||||
@@ -1757,11 +1921,11 @@ def GenerateSM80_TensorOp_1688(manifest, args):
|
||||
TileDescription([128, 64, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 16], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
@@ -1787,6 +1951,10 @@ def GenerateSM80_TensorOp_1688(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type_mixed, alignment_constraints)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 4)
|
||||
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type_mixed, 4)
|
||||
#
|
||||
|
||||
#
|
||||
@@ -1822,6 +1990,7 @@ def GenerateSM80_TensorOp_1688_fast_math(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [4, 2, 1]
|
||||
|
||||
@@ -1835,11 +2004,11 @@ def GenerateSM80_TensorOp_1688_fast_math(manifest, args):
|
||||
TileDescription([128, 64, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 16], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 16], 10, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 32], 4, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 128, 32], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
@@ -1850,6 +2019,8 @@ def GenerateSM80_TensorOp_1688_fast_math(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 4)
|
||||
#
|
||||
|
||||
#
|
||||
@@ -1875,22 +2046,23 @@ def GenerateSM80_SparseTensorOp_16816_fast_math(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [4, 2, 1]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 128, 32], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 256, 32], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 32], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 256, 32], 4, [1, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 32], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 32], 6, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([256, 64, 64], 3, [4, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 64], 3, [2, 4, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([256, 64, 64], 3, [4, 1, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 64], 4, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([ 64, 128, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 64], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
@@ -1971,13 +2143,14 @@ def GenerateSM80_TensorOp_884(manifest, args):
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
max_cc_smem_limited = 80
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([128, 128, 16], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 128, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 16], 3, [4, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([64, 128, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([128, 64, 16], 3, [2, 2, 1], math_inst, min_cc, max_cc_smem_limited),
|
||||
TileDescription([64, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([64, 32, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
@@ -2090,7 +2263,7 @@ def GenerateSM80_TensorOp_884_complex_gaussian(manifest, args):
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
def GenerateSM80_Simt(manifest, args):
|
||||
def GenerateSM80_Simt_f32(manifest, args):
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
@@ -2136,8 +2309,55 @@ def GenerateSM80_Simt(manifest, args):
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1)
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
def GenerateSM80_Simt_f64(manifest, args):
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
math_instructions = [
|
||||
MathInstruction( \
|
||||
[1, 1, 1], \
|
||||
DataType.f64, DataType.f64, DataType.f64, \
|
||||
OpcodeClass.Simt, \
|
||||
MathOperation.multiply_add),
|
||||
]
|
||||
|
||||
min_cc = 80
|
||||
max_cc = 1024
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
tile_descriptions = [
|
||||
TileDescription([128, 128, 8], 3, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 64, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 128, 8], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 64, 64, 8], 5, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 32, 8], 5, [2, 1, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([ 32, 128, 8], 5, [1, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
|
||||
data_type = [
|
||||
math_inst.element_a,
|
||||
math_inst.element_b,
|
||||
math_inst.element_accumulator,
|
||||
math_inst.element_accumulator,
|
||||
]
|
||||
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, \
|
||||
data_type, alignment_constraints)
|
||||
#
|
||||
|
||||
|
||||
##################################################################################################
|
||||
#
|
||||
def GenerateSM80_Simt_complex(manifest, args):
|
||||
@@ -2154,7 +2374,29 @@ def GenerateSM80_Simt_complex(manifest, args):
|
||||
|
||||
alignment_constraints = [1,]
|
||||
|
||||
data_type = [
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32
|
||||
]
|
||||
|
||||
layouts = [
|
||||
(LayoutType.ColumnMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.ColumnMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.ColumnMajor, LayoutType.ColumnMajor),
|
||||
(LayoutType.RowMajor, LayoutType.RowMajor, LayoutType.ColumnMajor),
|
||||
]
|
||||
|
||||
complex_transforms = [
|
||||
(ComplexTransform.none, ComplexTransform.none),
|
||||
(ComplexTransform.conj, ComplexTransform.none),
|
||||
(ComplexTransform.none, ComplexTransform.conj),
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
|
||||
for math_inst in math_instructions:
|
||||
|
||||
tile_descriptions = [
|
||||
TileDescription([128, 128, 8], 5, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([128, 128, 8], 4, [4, 2, 1], math_inst, min_cc, max_cc),
|
||||
@@ -2165,20 +2407,11 @@ def GenerateSM80_Simt_complex(manifest, args):
|
||||
TileDescription([32, 64, 16], 4, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
TileDescription([32, 32, 16], 5, [2, 2, 1], math_inst, min_cc, max_cc),
|
||||
]
|
||||
data_type = [
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32,
|
||||
DataType.cf32
|
||||
]
|
||||
|
||||
complex_transforms = [
|
||||
(ComplexTransform.none, ComplexTransform.none),
|
||||
(ComplexTransform.conj, ComplexTransform.none),
|
||||
(ComplexTransform.none, ComplexTransform.conj),
|
||||
(ComplexTransform.conj, ComplexTransform.conj)
|
||||
]
|
||||
CreateGemmOperator(manifest, layouts, tile_descriptions, data_type, alignment_constraints, complex_transforms)
|
||||
|
||||
conv_layout = (LayoutType.TensorNHWC, LayoutType.TensorNHWC, LayoutType.TensorNHWC)
|
||||
CreateConv2dOperator(manifest, conv_layout, tile_descriptions, data_type, 1)
|
||||
#
|
||||
|
||||
###################################################################################################
|
||||
@@ -2202,7 +2435,8 @@ def GenerateSM80(manifest, args):
|
||||
GenerateSM80_SparseTensorOp_168128_TN(manifest, args)
|
||||
GenerateSM80_TensorOp_16864_Interleaved(manifest, args)
|
||||
GenerateSM80_TensorOp_168256(manifest, args)
|
||||
GenerateSM80_Simt(manifest, args)
|
||||
GenerateSM80_Simt_f32(manifest, args)
|
||||
GenerateSM80_Simt_f64(manifest, args)
|
||||
GenerateSM80_Simt_complex(manifest, args)
|
||||
|
||||
###################################################################################################
|
||||
|
||||
@@ -71,6 +71,7 @@ class DataType(enum.Enum):
|
||||
cu16 = enum_auto()
|
||||
cu32 = enum_auto()
|
||||
cu64 = enum_auto()
|
||||
invalid = enum_auto()
|
||||
|
||||
#
|
||||
ShortDataTypeNames = {
|
||||
@@ -260,6 +261,8 @@ MathOperationTag = {
|
||||
class LayoutType(enum.Enum):
|
||||
ColumnMajor = enum_auto()
|
||||
RowMajor = enum_auto()
|
||||
ColumnMajorInterleaved2 = enum_auto()
|
||||
RowMajorInterleaved2 = enum_auto()
|
||||
ColumnMajorInterleaved32 = enum_auto()
|
||||
RowMajorInterleaved32 = enum_auto()
|
||||
ColumnMajorInterleaved64 = enum_auto()
|
||||
@@ -268,13 +271,17 @@ class LayoutType(enum.Enum):
|
||||
TensorNDHWC = enum_auto()
|
||||
TensorNCHW = enum_auto()
|
||||
TensorNGHWC = enum_auto()
|
||||
TensorNCxHW32 = enum_auto()
|
||||
TensorNCxHW64 = enum_auto()
|
||||
TensorNC32HW32 = enum_auto()
|
||||
TensorNC64HW64 = enum_auto()
|
||||
TensorC32RSK32 = enum_auto()
|
||||
TensorC64RSK64 = enum_auto()
|
||||
|
||||
#
|
||||
LayoutTag = {
|
||||
LayoutType.ColumnMajor: 'cutlass::layout::ColumnMajor',
|
||||
LayoutType.RowMajor: 'cutlass::layout::RowMajor',
|
||||
LayoutType.ColumnMajorInterleaved2: 'cutlass::layout::ColumnMajorInterleaved<2>',
|
||||
LayoutType.RowMajorInterleaved2: 'cutlass::layout::RowMajorInterleaved<2>',
|
||||
LayoutType.ColumnMajorInterleaved32: 'cutlass::layout::ColumnMajorInterleaved<32>',
|
||||
LayoutType.RowMajorInterleaved32: 'cutlass::layout::RowMajorInterleaved<32>',
|
||||
LayoutType.ColumnMajorInterleaved64: 'cutlass::layout::ColumnMajorInterleaved<64>',
|
||||
@@ -283,14 +290,18 @@ LayoutTag = {
|
||||
LayoutType.TensorNDHWC: 'cutlass::layout::TensorNDHWC',
|
||||
LayoutType.TensorNCHW: 'cutlass::layout::TensorNCHW',
|
||||
LayoutType.TensorNGHWC: 'cutlass::layout::TensorNGHWC',
|
||||
LayoutType.TensorNCxHW32: 'cutlass::layout::TensorNCxHW32',
|
||||
LayoutType.TensorNCxHW64: 'cutlass::layout::TensorNCxHW64'
|
||||
LayoutType.TensorNC32HW32: 'cutlass::layout::TensorNCxHWx<32>',
|
||||
LayoutType.TensorC32RSK32: 'cutlass::layout::TensorCxRSKx<32>',
|
||||
LayoutType.TensorNC64HW64: 'cutlass::layout::TensorNCxHWx<64>',
|
||||
LayoutType.TensorC64RSK64: 'cutlass::layout::TensorCxRSKx<64>',
|
||||
}
|
||||
|
||||
#
|
||||
TransposedLayout = {
|
||||
LayoutType.ColumnMajor: LayoutType.RowMajor,
|
||||
LayoutType.RowMajor: LayoutType.ColumnMajor,
|
||||
LayoutType.ColumnMajorInterleaved2: LayoutType.RowMajorInterleaved2,
|
||||
LayoutType.RowMajorInterleaved2: LayoutType.ColumnMajorInterleaved2,
|
||||
LayoutType.ColumnMajorInterleaved32: LayoutType.RowMajorInterleaved32,
|
||||
LayoutType.RowMajorInterleaved32: LayoutType.ColumnMajorInterleaved32,
|
||||
LayoutType.ColumnMajorInterleaved64: LayoutType.RowMajorInterleaved64,
|
||||
@@ -301,17 +312,21 @@ TransposedLayout = {
|
||||
#
|
||||
ShortLayoutTypeNames = {
|
||||
LayoutType.ColumnMajor: 'n',
|
||||
LayoutType.ColumnMajorInterleaved32: 'n2',
|
||||
LayoutType.ColumnMajorInterleaved32: 'n32',
|
||||
LayoutType.ColumnMajorInterleaved64: 'n64',
|
||||
LayoutType.RowMajor: 't',
|
||||
LayoutType.RowMajorInterleaved2: 't2',
|
||||
LayoutType.RowMajorInterleaved32: 't32',
|
||||
LayoutType.RowMajorInterleaved64: 't64',
|
||||
LayoutType.TensorNHWC: 'nhwc',
|
||||
LayoutType.TensorNDHWC: 'ndhwc',
|
||||
LayoutType.TensorNCHW: 'nchw',
|
||||
LayoutType.TensorNGHWC: 'nghwc',
|
||||
LayoutType.TensorNCxHW32: 'ncxhw32',
|
||||
LayoutType.TensorNCxHW64: 'ncxhw64'
|
||||
LayoutType.TensorNC32HW32: 'nc32hw32',
|
||||
LayoutType.TensorNC64HW64: 'nc64hw64',
|
||||
LayoutType.TensorC32RSK32: 'c32rsk32',
|
||||
LayoutType.TensorC64RSK64: 'c64rsk64'
|
||||
}
|
||||
|
||||
#
|
||||
@@ -346,9 +361,14 @@ OpcodeClassTag = {
|
||||
#
|
||||
class OperationKind(enum.Enum):
|
||||
Gemm = enum_auto()
|
||||
Conv2d = enum_auto()
|
||||
Conv3d = enum_auto()
|
||||
|
||||
#
|
||||
OperationKindNames = {
|
||||
OperationKind.Gemm: 'gemm'
|
||||
, OperationKind.Conv2d: 'conv2d'
|
||||
, OperationKind.Conv3d: 'conv3d'
|
||||
}
|
||||
|
||||
#
|
||||
@@ -424,6 +444,61 @@ SwizzlingFunctorTag = {
|
||||
SwizzlingFunctor.Identity4: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<4>',
|
||||
SwizzlingFunctor.Identity8: 'cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<8>',
|
||||
}
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
class ConvKind(enum.Enum):
|
||||
Fprop = enum_auto()
|
||||
Dgrad = enum_auto()
|
||||
Wgrad = enum_auto()
|
||||
|
||||
#
|
||||
ConvKindTag = {
|
||||
ConvKind.Fprop: 'cutlass::conv::Operator::kFprop',
|
||||
ConvKind.Dgrad: 'cutlass::conv::Operator::kDgrad',
|
||||
ConvKind.Wgrad: 'cutlass::conv::Operator::kWgrad'
|
||||
}
|
||||
|
||||
ConvKindNames = {
|
||||
ConvKind.Fprop: 'fprop',
|
||||
ConvKind.Dgrad: 'dgrad',
|
||||
ConvKind.Wgrad: 'wgrad',
|
||||
}
|
||||
|
||||
#
|
||||
class IteratorAlgorithm(enum.Enum):
|
||||
Analytic = enum_auto()
|
||||
Optimized = enum_auto()
|
||||
|
||||
#
|
||||
IteratorAlgorithmTag = {
|
||||
IteratorAlgorithm.Analytic: 'cutlass::conv::IteratorAlgorithm::kAnalytic',
|
||||
IteratorAlgorithm.Optimized: 'cutlass::conv::IteratorAlgorithm::kOptimized',
|
||||
}
|
||||
|
||||
IteratorAlgorithmNames = {
|
||||
IteratorAlgorithm.Analytic: 'analytic',
|
||||
IteratorAlgorithm.Optimized: 'optimized',
|
||||
}
|
||||
|
||||
#
|
||||
class StrideSupport(enum.Enum):
|
||||
Strided = enum_auto()
|
||||
Unity = enum_auto()
|
||||
|
||||
#
|
||||
StrideSupportTag = {
|
||||
StrideSupport.Strided: 'cutlass::conv::StrideSupport::kStrided',
|
||||
StrideSupport.Unity: 'cutlass::conv::StrideSupport::kUnity',
|
||||
}
|
||||
|
||||
StrideSupportNames = {
|
||||
StrideSupport.Strided: '',
|
||||
StrideSupport.Unity: 'unity_stride',
|
||||
}
|
||||
|
||||
|
||||
###################################################################################################
|
||||
|
||||
#
|
||||
|
||||
@@ -10,6 +10,9 @@ import shutil
|
||||
|
||||
from library import *
|
||||
from gemm_operation import *
|
||||
from conv2d_operation import *
|
||||
from conv3d_operation import *
|
||||
|
||||
###################################################################################################
|
||||
|
||||
class EmitOperationKindLibrary:
|
||||
@@ -20,6 +23,8 @@ class EmitOperationKindLibrary:
|
||||
|
||||
self.emitters = {
|
||||
OperationKind.Gemm: EmitGemmConfigurationLibrary
|
||||
, OperationKind.Conv2d: EmitConv2dConfigurationLibrary
|
||||
, OperationKind.Conv3d: EmitConv3dConfigurationLibrary
|
||||
}
|
||||
|
||||
self.configurations = [];
|
||||
@@ -112,7 +117,10 @@ class Manifest:
|
||||
def __init__(self, args):
|
||||
self.operations = {}
|
||||
self.args = args
|
||||
self.compute_capabilities = [int(x) for x in args.architectures.split(';')]
|
||||
|
||||
architectures = args.architectures.split(';') if len(args.architectures) else ['50',]
|
||||
self.compute_capabilities = [int(x) for x in architectures]
|
||||
|
||||
self.selected_kernels = []
|
||||
|
||||
if args.operations == 'all':
|
||||
@@ -121,6 +129,8 @@ class Manifest:
|
||||
|
||||
operations_list = [
|
||||
OperationKind.Gemm
|
||||
, OperationKind.Conv2d
|
||||
, OperationKind.Conv3d
|
||||
]
|
||||
|
||||
self.operations_enabled = [x for x in operations_list if OperationKindNames[x] in args.operations.split(',')]
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines operations for all CONV operation kinds in CUTLASS Library.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/conv/kernel/default_conv2d_fprop.h"
|
||||
#include "cutlass/conv/kernel/default_conv2d_dgrad.h"
|
||||
#include "cutlass/conv/kernel/default_conv2d_wgrad.h"
|
||||
#include "cutlass/conv/device/implicit_gemm_convolution.h"
|
||||
|
||||
#include "cutlass/library/library.h"
|
||||
#include "library_internal.h"
|
||||
#include "cutlass/util/host_tensor.h"
|
||||
|
||||
#include "cutlass/util/reference/host/convolution.h"
|
||||
#include "cutlass/util/reference/host/tensor_compare.h"
|
||||
#include "cutlass/core_io.h"
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Operator_>
|
||||
class Conv2dOperationBase : public Operation {
|
||||
public:
|
||||
|
||||
using Operator = Operator_;
|
||||
|
||||
using ElementA = typename Operator::ElementA;
|
||||
using LayoutA = typename Operator::LayoutA;
|
||||
using ElementB = typename Operator::ElementB;
|
||||
using LayoutB = typename Operator::LayoutB;
|
||||
using ElementC = typename Operator::ElementC;
|
||||
using LayoutC = typename Operator::LayoutC;
|
||||
using ElementAccumulator = typename Operator::ElementAccumulator;
|
||||
using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute;
|
||||
static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = Operator::kIteratorAlgorithm;
|
||||
static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator;
|
||||
|
||||
using OperatorArguments = typename Operator::Arguments;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
ConvDescription description_;
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
Conv2dOperationBase(char const *name = "unknown_conv2d") {
|
||||
|
||||
description_.name = name;
|
||||
description_.provider = Provider::kCUTLASS;
|
||||
description_.kind = OperationKind::kConv2d;
|
||||
description_.conv_dim = Operator::kConvDim;
|
||||
|
||||
description_.iterator_algorithm = IteratorAlgorithmMap<Operator::kIteratorAlgorithm>::kId;
|
||||
|
||||
description_.tile_description.threadblock_shape = make_Coord(
|
||||
Operator::ThreadblockShape::kM,
|
||||
Operator::ThreadblockShape::kN,
|
||||
Operator::ThreadblockShape::kK);
|
||||
|
||||
description_.tile_description.threadblock_stages = Operator::kStages;
|
||||
|
||||
description_.tile_description.warp_count = make_Coord(
|
||||
Operator::ImplicitGemmKernel::WarpCount::kM,
|
||||
Operator::ImplicitGemmKernel::WarpCount::kN,
|
||||
Operator::ImplicitGemmKernel::WarpCount::kK);
|
||||
|
||||
description_.tile_description.math_instruction.instruction_shape = make_Coord(
|
||||
Operator::InstructionShape::kM,
|
||||
Operator::InstructionShape::kN,
|
||||
Operator::InstructionShape::kK);
|
||||
|
||||
description_.tile_description.math_instruction.element_accumulator =
|
||||
NumericTypeMap<ElementAccumulator>::kId;
|
||||
|
||||
description_.tile_description.math_instruction.opcode_class =
|
||||
OpcodeClassMap<typename Operator::OperatorClass>::kId;
|
||||
|
||||
description_.tile_description.math_instruction.math_operation =
|
||||
MathOperationMap<typename Operator::MathOperator>::kId;
|
||||
|
||||
description_.tile_description.minimum_compute_capability =
|
||||
ArchMap<typename Operator::ArchTag, typename Operator::OperatorClass>::kMin;
|
||||
|
||||
description_.tile_description.maximum_compute_capability =
|
||||
ArchMap<typename Operator::ArchTag, typename Operator::OperatorClass>::kMax;
|
||||
|
||||
description_.A = make_TensorDescription<ElementA, LayoutA>();
|
||||
description_.B = make_TensorDescription<ElementB, LayoutB>();
|
||||
description_.C = make_TensorDescription<ElementC, LayoutC>();
|
||||
description_.element_epilogue = NumericTypeMap<ElementCompute>::kId;
|
||||
|
||||
// TODO: Add split k mode Serial and parallel to convolutions
|
||||
// description_.split_k_mode = Operator::kSplitK ? SplitKMode::kSerial : SplitKMode::kNone;
|
||||
|
||||
}
|
||||
|
||||
/// Returns the description of the GEMM operation
|
||||
virtual OperationDescription const & description() const {
|
||||
return description_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Conv2d library operation class for cutlass profiler
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Operator_>
|
||||
class Conv2dOperation : public Conv2dOperationBase<Operator_> {
|
||||
public:
|
||||
|
||||
using Operator = Operator_;
|
||||
|
||||
using ElementA = typename Operator::ElementA;
|
||||
using LayoutA = typename Operator::LayoutA;
|
||||
using ElementB = typename Operator::ElementB;
|
||||
using LayoutB = typename Operator::LayoutB;
|
||||
using ElementC = typename Operator::ElementC;
|
||||
using LayoutC = typename Operator::LayoutC;
|
||||
using ElementAccumulator = typename Operator::ElementAccumulator;
|
||||
using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute;
|
||||
static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator;
|
||||
|
||||
using OperatorArguments = typename Operator::Arguments;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
Conv2dOperation(char const *name = "unknown_conv2d_fprop") : Conv2dOperationBase<Operator_>(name) {
|
||||
this->description_.conv_kind = ConvKindMap<kConvolutionalOperator>::kId;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status construct_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
Conv2dConfiguration const *configuration) {
|
||||
|
||||
|
||||
operator_args.problem_size = configuration->problem_size;
|
||||
|
||||
operator_args.ref_A =
|
||||
{
|
||||
nullptr,
|
||||
LayoutA::packed(implicit_gemm_tensor_a_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.ref_B =
|
||||
{
|
||||
nullptr,
|
||||
LayoutB::packed(implicit_gemm_tensor_b_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.ref_C =
|
||||
{
|
||||
nullptr,
|
||||
LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.ref_D =
|
||||
{
|
||||
nullptr,
|
||||
LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.split_k_mode = configuration->split_k_mode;
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status update_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
ConvArguments const *arguments) {
|
||||
|
||||
if (arguments->pointer_mode == ScalarPointerMode::kHost) {
|
||||
typename Operator::EpilogueOutputOp::Params params(
|
||||
*static_cast<ElementCompute const *>(arguments->alpha),
|
||||
*static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.output_op = params;
|
||||
}
|
||||
else if (arguments->pointer_mode == ScalarPointerMode::kDevice){
|
||||
typename Operator::EpilogueOutputOp::Params params(
|
||||
static_cast<ElementCompute const *>(arguments->alpha),
|
||||
static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.output_op = params;
|
||||
}
|
||||
else {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
operator_args.ref_A.reset(static_cast<ElementA *>(const_cast<void *>(arguments->A)));
|
||||
operator_args.ref_B.reset(static_cast<ElementB *>(const_cast<void *>(arguments->B)));
|
||||
operator_args.ref_C.reset(static_cast<ElementC *>(const_cast<void *>(arguments->C)));
|
||||
operator_args.ref_D.reset(static_cast<ElementC *>(const_cast<void *>(arguments->D)));
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Returns success if the operation can proceed
|
||||
virtual Status can_implement(
|
||||
void const *configuration_ptr,
|
||||
void const *arguments_ptr) const {
|
||||
|
||||
Conv2dConfiguration const *configuration =
|
||||
static_cast<Conv2dConfiguration const *>(configuration_ptr);
|
||||
|
||||
ConvArguments const *arguments =
|
||||
static_cast<ConvArguments const *>(arguments_ptr);
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(args, configuration);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = update_arguments_(args, arguments);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return Operator::can_implement(args);
|
||||
|
||||
}
|
||||
|
||||
/// Gets the host-side workspace
|
||||
virtual uint64_t get_host_workspace_size(
|
||||
void const *configuration) const {
|
||||
|
||||
return sizeof(Operator);
|
||||
}
|
||||
|
||||
/// Gets the device-side workspace
|
||||
virtual uint64_t get_device_workspace_size(
|
||||
void const *configuration_ptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<Conv2dConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operator::get_workspace_size(args);
|
||||
}
|
||||
|
||||
/// Initializes the workspace
|
||||
virtual Status initialize(
|
||||
void const *configuration_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<Conv2dConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = new (host_workspace) Operator;
|
||||
//std::cout << "initialize library::Conv2dOperation" << std::endl;
|
||||
//print_operator_args(args);
|
||||
return op->initialize(args, device_workspace, stream);
|
||||
|
||||
}
|
||||
|
||||
/// Runs the kernel
|
||||
virtual Status run(
|
||||
void const *arguments_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace = nullptr,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = update_arguments_(
|
||||
args,
|
||||
static_cast<ConvArguments const *>(arguments_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = static_cast<Operator *>(host_workspace);
|
||||
|
||||
status = op->update(args, device_workspace);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
//std::cout << "run library::Conv2dOperation" << std::endl;
|
||||
//print_operator_args(args);
|
||||
return op->run(stream);
|
||||
}
|
||||
|
||||
/// Call print_operator_args from the Conv2dOperation::initialize()
|
||||
// to dump arguments passed on to cutlass operator for debugging
|
||||
void print_operator_args(OperatorArguments &operator_args) const {
|
||||
std::cout << "Conv2dOperation::OperatorArguments" << std::endl
|
||||
<< " problem_size:" << std::endl
|
||||
<< operator_args.problem_size << std::endl
|
||||
<< " split_k_mode: "
|
||||
<< (operator_args.split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial" : "parallel") << std::endl
|
||||
<< " epilouge (alpha, beta): "
|
||||
<< operator_args.output_op.alpha << ", "
|
||||
<< operator_args.output_op.beta << std::endl
|
||||
<< " ref_A (ptr, {stride}): "
|
||||
<< operator_args.ref_A.data() << ", {"
|
||||
<< operator_args.ref_A.stride(0) << ", "
|
||||
<< operator_args.ref_A.stride(1) << ", "
|
||||
<< operator_args.ref_A.stride(2) << "}" << std::endl
|
||||
<< " ref_B (ptr, {stride}): "
|
||||
<< operator_args.ref_B.data() << ", {"
|
||||
<< operator_args.ref_B.stride(0) << ", "
|
||||
<< operator_args.ref_B.stride(1) << ", "
|
||||
<< operator_args.ref_B.stride(2) << "}" << std::endl
|
||||
<< " ref_C (ptr, {stride}): "
|
||||
<< operator_args.ref_C.data() << ", {"
|
||||
<< operator_args.ref_C.stride(0) << ", "
|
||||
<< operator_args.ref_C.stride(1) << ", "
|
||||
<< operator_args.ref_C.stride(2) << "}" << std::endl
|
||||
<< " ref_D (ptr, {stride}): "
|
||||
<< operator_args.ref_D.data() << ", {"
|
||||
<< operator_args.ref_D.stride(0) << ", "
|
||||
<< operator_args.ref_D.stride(1) << ", "
|
||||
<< operator_args.ref_D.stride(2) << "}" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,378 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines operations for all CONV operation kinds in CUTLASS Library.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/conv/kernel/default_conv3d_fprop.h"
|
||||
#include "cutlass/conv/kernel/default_conv3d_dgrad.h"
|
||||
#include "cutlass/conv/kernel/default_conv3d_wgrad.h"
|
||||
#include "cutlass/conv/device/implicit_gemm_convolution.h"
|
||||
|
||||
#include "cutlass/library/library.h"
|
||||
#include "library_internal.h"
|
||||
#include "cutlass/util/host_tensor.h"
|
||||
|
||||
#include "cutlass/util/reference/host/convolution.h"
|
||||
#include "cutlass/util/reference/host/tensor_compare.h"
|
||||
#include "cutlass/core_io.h"
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Operator_>
|
||||
class Conv3dOperationBase : public Operation {
|
||||
public:
|
||||
|
||||
using Operator = Operator_;
|
||||
|
||||
using ElementA = typename Operator::ElementA;
|
||||
using LayoutA = typename Operator::LayoutA;
|
||||
using ElementB = typename Operator::ElementB;
|
||||
using LayoutB = typename Operator::LayoutB;
|
||||
using ElementC = typename Operator::ElementC;
|
||||
using LayoutC = typename Operator::LayoutC;
|
||||
using ElementAccumulator = typename Operator::ElementAccumulator;
|
||||
using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute;
|
||||
static cutlass::conv::IteratorAlgorithm const kIteratorAlgorithm = Operator::kIteratorAlgorithm;
|
||||
static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator;
|
||||
|
||||
using OperatorArguments = typename Operator::Arguments;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
ConvDescription description_;
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
Conv3dOperationBase(char const *name = "unknown_conv3d") {
|
||||
|
||||
description_.name = name;
|
||||
description_.provider = Provider::kCUTLASS;
|
||||
description_.kind = OperationKind::kConv3d;
|
||||
description_.conv_dim = Operator::kConvDim;
|
||||
|
||||
description_.iterator_algorithm = IteratorAlgorithmMap<Operator::kIteratorAlgorithm>::kId;
|
||||
|
||||
description_.tile_description.threadblock_shape = make_Coord(
|
||||
Operator::ThreadblockShape::kM,
|
||||
Operator::ThreadblockShape::kN,
|
||||
Operator::ThreadblockShape::kK);
|
||||
|
||||
description_.tile_description.threadblock_stages = Operator::kStages;
|
||||
|
||||
description_.tile_description.warp_count = make_Coord(
|
||||
Operator::ImplicitGemmKernel::WarpCount::kM,
|
||||
Operator::ImplicitGemmKernel::WarpCount::kN,
|
||||
Operator::ImplicitGemmKernel::WarpCount::kK);
|
||||
|
||||
description_.tile_description.math_instruction.instruction_shape = make_Coord(
|
||||
Operator::InstructionShape::kM,
|
||||
Operator::InstructionShape::kN,
|
||||
Operator::InstructionShape::kK);
|
||||
|
||||
description_.tile_description.math_instruction.element_accumulator =
|
||||
NumericTypeMap<ElementAccumulator>::kId;
|
||||
|
||||
description_.tile_description.math_instruction.opcode_class =
|
||||
OpcodeClassMap<typename Operator::OperatorClass>::kId;
|
||||
|
||||
description_.tile_description.minimum_compute_capability =
|
||||
ArchMap<typename Operator::ArchTag, typename Operator::OperatorClass>::kMin;
|
||||
|
||||
description_.tile_description.maximum_compute_capability =
|
||||
ArchMap<typename Operator::ArchTag, typename Operator::OperatorClass>::kMax;
|
||||
|
||||
description_.A = make_TensorDescription<ElementA, LayoutA>();
|
||||
description_.B = make_TensorDescription<ElementB, LayoutB>();
|
||||
description_.C = make_TensorDescription<ElementC, LayoutC>();
|
||||
description_.element_epilogue = NumericTypeMap<ElementCompute>::kId;
|
||||
|
||||
}
|
||||
|
||||
/// Returns the description of the GEMM operation
|
||||
virtual OperationDescription const & description() const {
|
||||
return description_;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Conv2d library operation class for cutlass profiler
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template <typename Operator_>
|
||||
class Conv3dOperation : public Conv3dOperationBase<Operator_> {
|
||||
public:
|
||||
|
||||
using Operator = Operator_;
|
||||
|
||||
using ElementA = typename Operator::ElementA;
|
||||
using LayoutA = typename Operator::LayoutA;
|
||||
using ElementB = typename Operator::ElementB;
|
||||
using LayoutB = typename Operator::LayoutB;
|
||||
using ElementC = typename Operator::ElementC;
|
||||
using LayoutC = typename Operator::LayoutC;
|
||||
using ElementAccumulator = typename Operator::ElementAccumulator;
|
||||
using ElementCompute = typename Operator::EpilogueOutputOp::ElementCompute;
|
||||
static cutlass::conv::Operator const kConvolutionalOperator = Operator::kConvolutionalOperator;
|
||||
|
||||
using OperatorArguments = typename Operator::Arguments;
|
||||
|
||||
public:
|
||||
/// Constructor
|
||||
Conv3dOperation(char const *name = "unknown_conv3d_fprop") : Conv3dOperationBase<Operator_>(name) {
|
||||
this->description_.conv_kind = ConvKindMap<kConvolutionalOperator>::kId;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status construct_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
Conv3dConfiguration const *configuration) {
|
||||
|
||||
|
||||
operator_args.problem_size = configuration->problem_size;
|
||||
|
||||
operator_args.ref_A =
|
||||
{
|
||||
nullptr,
|
||||
LayoutA::packed(implicit_gemm_tensor_a_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.ref_B =
|
||||
{
|
||||
nullptr,
|
||||
LayoutB::packed(implicit_gemm_tensor_b_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.ref_C =
|
||||
{
|
||||
nullptr,
|
||||
LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.ref_D =
|
||||
{
|
||||
nullptr,
|
||||
LayoutC::packed(implicit_gemm_tensor_c_extent(kConvolutionalOperator, configuration->problem_size))
|
||||
};
|
||||
|
||||
operator_args.split_k_mode = configuration->split_k_mode;
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status update_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
ConvArguments const *arguments) {
|
||||
|
||||
if (arguments->pointer_mode == ScalarPointerMode::kHost) {
|
||||
typename Operator::EpilogueOutputOp::Params params(
|
||||
*static_cast<ElementCompute const *>(arguments->alpha),
|
||||
*static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.output_op = params;
|
||||
}
|
||||
else if (arguments->pointer_mode == ScalarPointerMode::kDevice){
|
||||
typename Operator::EpilogueOutputOp::Params params(
|
||||
static_cast<ElementCompute const *>(arguments->alpha),
|
||||
static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.output_op = params;
|
||||
}
|
||||
else {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
operator_args.ref_A.reset(static_cast<ElementA *>(const_cast<void *>(arguments->A)));
|
||||
operator_args.ref_B.reset(static_cast<ElementB *>(const_cast<void *>(arguments->B)));
|
||||
operator_args.ref_C.reset(static_cast<ElementC *>(const_cast<void *>(arguments->C)));
|
||||
operator_args.ref_D.reset(static_cast<ElementC *>(const_cast<void *>(arguments->D)));
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Returns success if the operation can proceed
|
||||
virtual Status can_implement(
|
||||
void const *configuration_ptr,
|
||||
void const *arguments_ptr) const {
|
||||
|
||||
Conv3dConfiguration const *configuration =
|
||||
static_cast<Conv3dConfiguration const *>(configuration_ptr);
|
||||
|
||||
ConvArguments const *arguments =
|
||||
static_cast<ConvArguments const *>(arguments_ptr);
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(args, configuration);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = update_arguments_(args, arguments);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return Operator::can_implement(args);
|
||||
|
||||
}
|
||||
|
||||
/// Gets the host-side workspace
|
||||
virtual uint64_t get_host_workspace_size(
|
||||
void const *configuration) const {
|
||||
|
||||
return sizeof(Operator);
|
||||
}
|
||||
|
||||
/// Gets the device-side workspace
|
||||
virtual uint64_t get_device_workspace_size(
|
||||
void const *configuration_ptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<Conv3dConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operator::get_workspace_size(args);
|
||||
}
|
||||
|
||||
/// Initializes the workspace
|
||||
virtual Status initialize(
|
||||
void const *configuration_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<Conv3dConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = new (host_workspace) Operator;
|
||||
//std::cout << "initialize library::Conv3dOperation" << std::endl;
|
||||
//print_operator_args(args);
|
||||
return op->initialize(args, device_workspace, stream);
|
||||
|
||||
}
|
||||
|
||||
/// Runs the kernel
|
||||
virtual Status run(
|
||||
void const *arguments_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace = nullptr,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = update_arguments_(
|
||||
args,
|
||||
static_cast<ConvArguments const *>(arguments_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = static_cast<Operator *>(host_workspace);
|
||||
|
||||
status = op->update(args, device_workspace);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
//std::cout << "run library::Conv3dOperation" << std::endl;
|
||||
//print_operator_args(args);
|
||||
return op->run(stream);
|
||||
}
|
||||
|
||||
/// Call print_operator_args from the Conv3dOperation::initialize()
|
||||
// to dump arguments passed on to cutlass operator for debugging
|
||||
void print_operator_args(OperatorArguments &operator_args) const {
|
||||
std::cout << "Conv3dOperation::OperatorArguments" << std::endl
|
||||
<< " problem_size: "
|
||||
<< operator_args.problem_size << std::endl
|
||||
<< " split_k_mode: "
|
||||
<< (operator_args.split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial" : "parallel") << std::endl
|
||||
<< " epilouge (alpha, beta): "
|
||||
<< operator_args.output_op.alpha << ", "
|
||||
<< operator_args.output_op.beta << std::endl
|
||||
<< " ref_A (ptr, {stride}): "
|
||||
<< operator_args.ref_A.data() << ", {"
|
||||
<< operator_args.ref_A.stride(0) << ", "
|
||||
<< operator_args.ref_A.stride(1) << ", "
|
||||
<< operator_args.ref_A.stride(2) << ", "
|
||||
<< operator_args.ref_A.stride(3) << "}" << std::endl
|
||||
<< " ref_B (ptr, {stride}): "
|
||||
<< operator_args.ref_B.data() << ", {"
|
||||
<< operator_args.ref_B.stride(0) << ", "
|
||||
<< operator_args.ref_B.stride(1) << ", "
|
||||
<< operator_args.ref_B.stride(2) << ", "
|
||||
<< operator_args.ref_B.stride(3) << "}" << std::endl
|
||||
<< " ref_C (ptr, {stride}): "
|
||||
<< operator_args.ref_C.data() << ", {"
|
||||
<< operator_args.ref_C.stride(0) << ", "
|
||||
<< operator_args.ref_C.stride(1) << ", "
|
||||
<< operator_args.ref_C.stride(2) << ", "
|
||||
<< operator_args.ref_C.stride(3) << "}" << std::endl
|
||||
<< " ref_D (ptr, {stride}): "
|
||||
<< operator_args.ref_D.data() << ", {"
|
||||
<< operator_args.ref_D.stride(0) << ", "
|
||||
<< operator_args.ref_D.stride(1) << ", "
|
||||
<< operator_args.ref_D.stride(2) << ", "
|
||||
<< operator_args.ref_D.stride(3) << "}" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1037,8 +1037,70 @@ Status Handle::gemm_planar_complex_array(
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Finds conv operation instances with Conv::ElementC = Reduction::ElementWorkspace
|
||||
Operation const* find_conv_operation_for_parallel_reduction(Operation const *operation) {
|
||||
|
||||
ConvDescription const &conv_desc =
|
||||
static_cast<ConvDescription const &>(operation->description());
|
||||
|
||||
// if the curren conv operation accumulator and output data type match return operation
|
||||
if(conv_desc.tile_description.math_instruction.element_accumulator == conv_desc.C.element) {
|
||||
return operation;
|
||||
}
|
||||
|
||||
// find conv operation to match conv output and reduction workspace data type
|
||||
ConvFunctionalKey key(
|
||||
library::Provider::kCUTLASS,
|
||||
conv_desc.conv_kind,
|
||||
conv_desc.A.element,
|
||||
conv_desc.A.layout,
|
||||
conv_desc.B.element,
|
||||
conv_desc.B.layout,
|
||||
conv_desc.tile_description.math_instruction.element_accumulator,
|
||||
conv_desc.C.layout,
|
||||
conv_desc.tile_description.math_instruction.element_accumulator,
|
||||
conv_desc.element_epilogue);
|
||||
|
||||
// conv operation table for conv2d or conv3d
|
||||
auto conv_operations = (conv_desc.kind == OperationKind::kConv2d) ?
|
||||
Singleton::get().operation_table.conv2d_operations :
|
||||
Singleton::get().operation_table.conv3d_operations;
|
||||
|
||||
// find ConvFunctionalKey in convolution operation table
|
||||
auto operators_it = conv_operations.find(key);
|
||||
|
||||
if (operators_it == conv_operations.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (operators_it->second.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// conv operation for same compute capability and iterator algorithm
|
||||
ConvPreferenceKey preference_key(
|
||||
conv_desc.tile_description.minimum_compute_capability,
|
||||
conv_desc.iterator_algorithm);
|
||||
|
||||
auto it = operators_it->second.find(preference_key);
|
||||
|
||||
if(it == operators_it->second.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// return matching conv opertion (same tile sizes and instruction)
|
||||
for (auto op : it->second) {
|
||||
if (op->description().tile_description == operation->description().tile_description) {
|
||||
return op;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -227,6 +227,23 @@ template <> struct LayoutMap<cutlass::layout::TensorNHWC> {
|
||||
template <> struct LayoutMap<cutlass::layout::TensorNDHWC> {
|
||||
static LayoutTypeID const kId = LayoutTypeID::kTensorNDHWC;
|
||||
};
|
||||
|
||||
template <> struct LayoutMap<cutlass::layout::TensorNCxHWx<32>> {
|
||||
static LayoutTypeID const kId = LayoutTypeID::kTensorNC32HW32;
|
||||
};
|
||||
|
||||
template <> struct LayoutMap<cutlass::layout::TensorNCxHWx<64>> {
|
||||
static LayoutTypeID const kId = LayoutTypeID::kTensorNC64HW64;
|
||||
};
|
||||
|
||||
template <> struct LayoutMap<cutlass::layout::TensorCxRSKx<32>> {
|
||||
static LayoutTypeID const kId = LayoutTypeID::kTensorC32RSK32;
|
||||
};
|
||||
|
||||
template <> struct LayoutMap<cutlass::layout::TensorCxRSKx<64>> {
|
||||
static LayoutTypeID const kId = LayoutTypeID::kTensorC64RSK64;
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename T> struct OpcodeClassMap;
|
||||
@@ -257,6 +274,43 @@ template <> struct ComplexTransformMap<cutlass::ComplexTransform::kConjugate> {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <cutlass::conv::Mode T> struct ConvModeMap;
|
||||
|
||||
template <> struct ConvModeMap<conv::Mode::kCrossCorrelation> {
|
||||
static ConvModeID const kId = ConvModeID::kCrossCorrelation;
|
||||
};
|
||||
|
||||
template <> struct ConvModeMap<conv::Mode::kConvolution> {
|
||||
static ConvModeID const kId = ConvModeID::kConvolution;
|
||||
};
|
||||
|
||||
|
||||
template <cutlass::conv::Operator T> struct ConvKindMap;
|
||||
|
||||
template <> struct ConvKindMap<conv::Operator::kFprop> {
|
||||
static ConvKind const kId = ConvKind::kFprop;
|
||||
};
|
||||
|
||||
template <> struct ConvKindMap<conv::Operator::kDgrad> {
|
||||
static ConvKind const kId = ConvKind::kDgrad;
|
||||
};
|
||||
|
||||
template <> struct ConvKindMap<conv::Operator::kWgrad> {
|
||||
static ConvKind const kId = ConvKind::kWgrad;
|
||||
};
|
||||
|
||||
|
||||
template <cutlass::conv::IteratorAlgorithm T> struct IteratorAlgorithmMap;
|
||||
|
||||
template <> struct IteratorAlgorithmMap<conv::IteratorAlgorithm::kAnalytic> {
|
||||
static IteratorAlgorithmID const kId = IteratorAlgorithmID::kAnalytic;
|
||||
};
|
||||
|
||||
template <> struct IteratorAlgorithmMap<conv::IteratorAlgorithm::kOptimized> {
|
||||
static IteratorAlgorithmID const kId = IteratorAlgorithmID::kOptimized;
|
||||
};
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Element, typename Layout>
|
||||
TensorDescription make_TensorDescription(int alignment = 1) {
|
||||
TensorDescription desc;
|
||||
|
||||
@@ -36,6 +36,11 @@ namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initialize_reference_operations(Manifest &manifest);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Top-level initialization
|
||||
Status Manifest::initialize() {
|
||||
|
||||
@@ -46,6 +51,12 @@ Status Manifest::initialize() {
|
||||
// initialize procedurally generated cutlass op in manifest object
|
||||
initialize_all(*this);
|
||||
|
||||
// initialize manually instanced conv3d reference op in manifest object
|
||||
initialize_reference_operations(*this);
|
||||
|
||||
// initialize manually instanced reduction reference op in manifest object
|
||||
initialize_all_reduction_op(*this);
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +76,55 @@ void OperationTable::append(Manifest const &manifest) {
|
||||
}
|
||||
|
||||
|
||||
// insert all conv2d or conv3d operation into operation table
|
||||
if (desc.kind == OperationKind::kConv2d || desc.kind == OperationKind::kConv3d) {
|
||||
auto &conv_desc = static_cast<library::ConvDescription const &>(desc);
|
||||
|
||||
ConvFunctionalKey functional_key(
|
||||
conv_desc.provider,
|
||||
conv_desc.conv_kind,
|
||||
conv_desc.A.element,
|
||||
conv_desc.A.layout,
|
||||
conv_desc.B.element,
|
||||
conv_desc.B.layout,
|
||||
conv_desc.C.element,
|
||||
conv_desc.C.layout,
|
||||
conv_desc.tile_description.math_instruction.element_accumulator,
|
||||
conv_desc.element_epilogue
|
||||
);
|
||||
|
||||
Operation const *op = operation.get();
|
||||
|
||||
int cc = conv_desc.tile_description.minimum_compute_capability;
|
||||
|
||||
ConvPreferenceKey preference_key(cc, conv_desc.iterator_algorithm);
|
||||
|
||||
// insert conv operation to conv2d_operations or conv3d_operations map
|
||||
(desc.kind == OperationKind::kConv2d) ?
|
||||
conv2d_operations[functional_key][preference_key].push_back(op) :
|
||||
conv3d_operations[functional_key][preference_key].push_back(op);
|
||||
}
|
||||
|
||||
// insert all reduction operation into operation table
|
||||
if (desc.kind == OperationKind::kReduction) {
|
||||
auto &reduce_desc = static_cast<library::ReductionDescription const &>(desc);
|
||||
|
||||
ReductionFunctionalKey functional_key(
|
||||
reduce_desc.provider,
|
||||
reduce_desc.element_workspace,
|
||||
reduce_desc.tile_description.math_instruction.element_accumulator,
|
||||
reduce_desc.element_output,
|
||||
reduce_desc.element_epilogue,
|
||||
library::MathOperationID::kAdd,
|
||||
library::EpilogueKind::kLinearCombination
|
||||
);
|
||||
|
||||
Operation const *op = operation.get();
|
||||
|
||||
reduction_operations[functional_key] = op;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Initialize operations for reduction operation in CUTLASS Library.
|
||||
|
||||
*/
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CUTLASS Reduction Instances //
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
void initialize_reduce_add_linear_combination_f32_f32_f16(Manifest &manifest);
|
||||
void initialize_reduce_add_linear_combination_f32_f32_f32(Manifest &manifest);
|
||||
void initialize_reduce_add_linear_combination_cf32_cf32_cf32(Manifest &manifest);
|
||||
|
||||
//
|
||||
// Entry point to construct operations
|
||||
//
|
||||
void initialize_all_reduction_op(Manifest &manifest) {
|
||||
|
||||
initialize_reduce_add_linear_combination_f32_f32_f16(manifest);
|
||||
initialize_reduce_add_linear_combination_f32_f32_f32(manifest);
|
||||
initialize_reduce_add_linear_combination_cf32_cf32_cf32(manifest);
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
@@ -0,0 +1,145 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines operations for reduction operation in CUTLASS Library.
|
||||
*/
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
#include "reduction_operation.h"
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
// naming convention initialize_reduce_[ReductionOp]_[EpilogueOp]_[ElementWorkspace]_[ElementAccumulator]_[ElementOutput]
|
||||
|
||||
void initialize_reduce_add_linear_combination_f32_f32_f16(Manifest &manifest) {
|
||||
|
||||
using ElementWorkspace = float;
|
||||
using ElementAccumulator = float;
|
||||
using ElementOutput = cutlass::half_t;
|
||||
using ElementCompute = float;
|
||||
|
||||
using EpilogueOutputOp = cutlass::epilogue::thread::LinearCombination<
|
||||
ElementOutput,
|
||||
128 / cutlass::sizeof_bits<ElementOutput>::value,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>;
|
||||
|
||||
using ReductionOp = cutlass::reduction::thread::ReduceAdd<
|
||||
ElementAccumulator,
|
||||
typename EpilogueOutputOp::ElementAccumulator,
|
||||
EpilogueOutputOp::kCount
|
||||
>;
|
||||
|
||||
using Operation_reduce_add_linear_combination_f32_f32_f16 = cutlass::reduction::device::ReduceSplitK<
|
||||
cutlass::reduction::kernel::ReduceSplitK<
|
||||
cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>,
|
||||
EpilogueOutputOp,
|
||||
ReductionOp
|
||||
>
|
||||
>;
|
||||
|
||||
manifest.append(new ReductionOperation<
|
||||
Operation_reduce_add_linear_combination_f32_f32_f16>(
|
||||
"reduce_add_linear_combination_f32_f32_f16"
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
void initialize_reduce_add_linear_combination_f32_f32_f32(Manifest &manifest) {
|
||||
|
||||
using ElementWorkspace = float;
|
||||
using ElementAccumulator = float;
|
||||
using ElementOutput = float;
|
||||
using ElementCompute = float;
|
||||
|
||||
using EpilogueOutputOp = cutlass::epilogue::thread::LinearCombination<
|
||||
ElementOutput,
|
||||
128 / cutlass::sizeof_bits<ElementOutput>::value,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>;
|
||||
|
||||
using ReductionOp = cutlass::reduction::thread::ReduceAdd<
|
||||
ElementAccumulator,
|
||||
typename EpilogueOutputOp::ElementAccumulator,
|
||||
EpilogueOutputOp::kCount
|
||||
>;
|
||||
|
||||
using Operation_reduce_add_linear_combination_f32_f32_f32 = cutlass::reduction::device::ReduceSplitK<
|
||||
cutlass::reduction::kernel::ReduceSplitK<
|
||||
cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>,
|
||||
EpilogueOutputOp,
|
||||
ReductionOp
|
||||
>
|
||||
>;
|
||||
|
||||
manifest.append(new ReductionOperation<
|
||||
Operation_reduce_add_linear_combination_f32_f32_f32>(
|
||||
"reduce_add_linear_combination_f32_f32_f32"
|
||||
));
|
||||
}
|
||||
|
||||
void initialize_reduce_add_linear_combination_cf32_cf32_cf32(Manifest &manifest) {
|
||||
|
||||
using ElementWorkspace = cutlass::complex<float>;
|
||||
using ElementAccumulator = cutlass::complex<float>;
|
||||
using ElementOutput = cutlass::complex<float>;
|
||||
using ElementCompute = cutlass::complex<float>;
|
||||
|
||||
using EpilogueOutputOp = cutlass::epilogue::thread::LinearCombination<
|
||||
ElementOutput,
|
||||
128 / cutlass::sizeof_bits<ElementOutput>::value,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>;
|
||||
|
||||
using ReductionOp = cutlass::reduction::thread::ReduceAdd<
|
||||
ElementAccumulator,
|
||||
typename EpilogueOutputOp::ElementAccumulator,
|
||||
EpilogueOutputOp::kCount
|
||||
>;
|
||||
|
||||
using Operation_reduce_add_linear_combination_cf32_cf32_cf32 = cutlass::reduction::device::ReduceSplitK<
|
||||
cutlass::reduction::kernel::ReduceSplitK<
|
||||
cutlass::MatrixShape<4, 32 * EpilogueOutputOp::kCount>,
|
||||
EpilogueOutputOp,
|
||||
ReductionOp
|
||||
>
|
||||
>;
|
||||
|
||||
manifest.append(new ReductionOperation<
|
||||
Operation_reduce_add_linear_combination_cf32_cf32_cf32>(
|
||||
"reduce_add_linear_combination_cf32_cf32_cf32"
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines operations for reduction operation in CUTLASS Library.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/epilogue/thread/linear_combination.h"
|
||||
#include "cutlass/reduction/thread/reduction_operators.h"
|
||||
#include "cutlass/reduction/device/reduce_split_k.h"
|
||||
|
||||
#include "cutlass/library/library.h"
|
||||
#include "library_internal.h"
|
||||
#include "cutlass/core_io.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Operator_>
|
||||
class ReductionOperation : public Operation {
|
||||
public:
|
||||
using Operator = Operator_;
|
||||
|
||||
using ElementWorkspace = typename Operator::ElementWorkspace;
|
||||
using ElementAccumulator = typename Operator::ElementAccumulator;
|
||||
using ElementOutput = typename Operator::ElementOutput;
|
||||
|
||||
using ElementCompute = typename Operator::OutputOp::ElementCompute;
|
||||
|
||||
using OperatorArguments = typename Operator::Arguments;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
ReductionDescription description_;
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
ReductionOperation(char const *name = "unknown_reduction") {
|
||||
|
||||
description_.name = name;
|
||||
description_.provider = Provider::kCUTLASS;
|
||||
description_.kind = OperationKind::kReduction;
|
||||
|
||||
description_.tile_description.threadblock_shape = make_Coord(Operator::Shape::kRow, Operator::Shape::kColumn, 1);
|
||||
|
||||
description_.tile_description.math_instruction.instruction_shape = make_Coord(1, 1, 1);
|
||||
description_.tile_description.math_instruction.element_accumulator = NumericTypeMap<ElementAccumulator>::kId;
|
||||
description_.tile_description.math_instruction.opcode_class = OpcodeClassID::kSimt;
|
||||
description_.tile_description.math_instruction.math_operation = MathOperationID::kAdd;
|
||||
|
||||
description_.tile_description.minimum_compute_capability = 50;
|
||||
description_.tile_description.maximum_compute_capability = 1024;
|
||||
|
||||
description_.element_workspace = NumericTypeMap<ElementWorkspace>::kId;
|
||||
description_.element_output = NumericTypeMap<ElementOutput>::kId;
|
||||
description_.element_epilogue = NumericTypeMap<ElementCompute>::kId;
|
||||
|
||||
}
|
||||
|
||||
/// Returns the description of the Reduction operation
|
||||
virtual OperationDescription const & description() const {
|
||||
return description_;
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status construct_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
ReductionConfiguration const *configuration) {
|
||||
|
||||
operator_args.problem_size = configuration->problem_size;
|
||||
operator_args.partitions = configuration->partitions;
|
||||
operator_args.partition_stride = configuration->partition_stride;
|
||||
|
||||
operator_args.workspace = {nullptr, int(configuration->ldw)};
|
||||
operator_args.source = {nullptr, int(configuration->lds)};
|
||||
operator_args.destination = {nullptr, int(configuration->ldd)};
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
/// Constructs the arguments structure given the configuration and arguments
|
||||
static Status update_arguments_(
|
||||
OperatorArguments &operator_args,
|
||||
ReductionArguments const *arguments) {
|
||||
|
||||
if (arguments->pointer_mode == ScalarPointerMode::kHost) {
|
||||
typename Operator::OutputOp::Params params(
|
||||
*static_cast<ElementCompute const *>(arguments->alpha),
|
||||
*static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.output = params;
|
||||
}
|
||||
else if (arguments->pointer_mode == ScalarPointerMode::kDevice){
|
||||
typename Operator::OutputOp::Params params(
|
||||
static_cast<ElementCompute const *>(arguments->alpha),
|
||||
static_cast<ElementCompute const *>(arguments->beta)
|
||||
);
|
||||
operator_args.output = params;
|
||||
}
|
||||
else {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
operator_args.workspace.reset(static_cast<ElementWorkspace *>(const_cast<void *>(arguments->workspace)));
|
||||
operator_args.source.reset(static_cast<ElementOutput *>(const_cast<void *>(arguments->source)));
|
||||
operator_args.destination.reset(static_cast<ElementOutput *>(const_cast<void *>(arguments->destination)));
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/// Returns success if the operation can proceed
|
||||
virtual Status can_implement(
|
||||
void const *configuration_ptr,
|
||||
void const *arguments_ptr) const {
|
||||
|
||||
ReductionConfiguration const *configuration =
|
||||
static_cast<ReductionConfiguration const *>(configuration_ptr);
|
||||
|
||||
ReductionArguments const *arguments =
|
||||
static_cast<ReductionArguments const *>(arguments_ptr);
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(args, configuration);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
status = update_arguments_(args, arguments);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
return Operator::can_implement(args);
|
||||
}
|
||||
|
||||
/// Gets the host-side workspace
|
||||
virtual uint64_t get_host_workspace_size(
|
||||
void const *configuration) const {
|
||||
|
||||
return sizeof(Operator);
|
||||
}
|
||||
|
||||
/// Gets the device-side workspace
|
||||
virtual uint64_t get_device_workspace_size(
|
||||
void const *configuration_ptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<ReductionConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Operator::get_workspace_size(args);
|
||||
}
|
||||
|
||||
/// Initializes the workspace
|
||||
virtual Status initialize(
|
||||
void const *configuration_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = construct_arguments_(
|
||||
args,
|
||||
static_cast<ReductionConfiguration const *>(configuration_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = new (host_workspace) Operator;
|
||||
//std::cout << "initialize library::Reduction" << std::endl;
|
||||
//print_operator_args(args);
|
||||
return op->initialize(args, device_workspace, stream);
|
||||
}
|
||||
|
||||
/// Runs the kernel
|
||||
virtual Status run(
|
||||
void const *arguments_ptr,
|
||||
void *host_workspace,
|
||||
void *device_workspace = nullptr,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
OperatorArguments args;
|
||||
|
||||
Status status = update_arguments_(
|
||||
args,
|
||||
static_cast<ReductionArguments const *>(arguments_ptr));
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
Operator *op = static_cast<Operator *>(host_workspace);
|
||||
|
||||
status = op->update(args, device_workspace);
|
||||
|
||||
if (status != Status::kSuccess) {
|
||||
return status;
|
||||
}
|
||||
|
||||
//std::cout << "run library::Reduction" << std::endl;
|
||||
//print_operator_args(args);
|
||||
return op->run(stream);
|
||||
}
|
||||
|
||||
/// Call print_operator_args from the Reduction::initialize()
|
||||
// to dump arguments passed on to cutlass operator for debugging
|
||||
void print_operator_args(OperatorArguments &operator_args) const {
|
||||
std::cout << "Reduction::OperatorArguments" << std::endl
|
||||
<< " problem_size: "
|
||||
<< operator_args.problem_size << std::endl
|
||||
<< " partitions: "
|
||||
<< operator_args.partitions << std::endl
|
||||
<< " partition_stride: "
|
||||
<< operator_args.partition_stride << std::endl
|
||||
<< " epilouge (alpha, beta): "
|
||||
<< operator_args.output.alpha << ", "
|
||||
<< operator_args.output.beta << std::endl
|
||||
<< " workspace (ptr, stride): "
|
||||
<< operator_args.workspace.data() << ", "
|
||||
<< operator_args.workspace.stride(0) << std::endl
|
||||
<< " source (ptr, stride): "
|
||||
<< operator_args.source.data() << ", "
|
||||
<< operator_args.source.stride(0) << std::endl
|
||||
<< " destination (ptr, stride): "
|
||||
<< operator_args.destination.data() << ", "
|
||||
<< operator_args.destination.stride(0) << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -0,0 +1,223 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief
|
||||
|
||||
*/
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
#include "conv_reference_operation.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initialize_conv2d_reference_operations(Manifest &manifest) {
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::half_t,
|
||||
cutlass::half_t
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNHWC,
|
||||
float, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNHWC,
|
||||
float, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNHWC,
|
||||
float, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
float, cutlass::layout::TensorNHWC,
|
||||
float, cutlass::layout::TensorNHWC,
|
||||
float, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
2,
|
||||
cutlass::complex<float>, cutlass::layout::TensorNHWC,
|
||||
cutlass::complex<float>, cutlass::layout::TensorNHWC,
|
||||
cutlass::complex<float>, cutlass::layout::TensorNHWC,
|
||||
cutlass::complex<float>,
|
||||
cutlass::complex<float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
int8_t, cutlass::layout::TensorNHWC,
|
||||
int8_t, cutlass::layout::TensorNHWC,
|
||||
int32_t, cutlass::layout::TensorNHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
int8_t, cutlass::layout::TensorNHWC,
|
||||
int8_t, cutlass::layout::TensorNHWC,
|
||||
int8_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<int8_t, float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
uint8_t, cutlass::layout::TensorNHWC,
|
||||
uint8_t, cutlass::layout::TensorNHWC,
|
||||
uint8_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<uint8_t, float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
uint8_t, cutlass::layout::TensorNHWC,
|
||||
uint8_t, cutlass::layout::TensorNHWC,
|
||||
int32_t, cutlass::layout::TensorNHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
uint8_t, cutlass::layout::TensorNHWC,
|
||||
uint8_t, cutlass::layout::TensorNHWC,
|
||||
int8_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<int8_t, float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNHWC,
|
||||
int32_t, cutlass::layout::TensorNHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<cutlass::int4b_t, float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNHWC,
|
||||
int32_t, cutlass::layout::TensorNHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
2,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNHWC,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<cutlass::uint4b_t, float>
|
||||
>(manifest);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief
|
||||
*/
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
#include "conv_reference_operation.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initialize_conv3d_reference_operations(Manifest &manifest) {
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::half_t,
|
||||
cutlass::half_t
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::half_t, cutlass::layout::TensorNDHWC,
|
||||
float, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::bfloat16_t, cutlass::layout::TensorNDHWC,
|
||||
float, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::tfloat32_t, cutlass::layout::TensorNDHWC,
|
||||
float, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_all<
|
||||
3,
|
||||
float, cutlass::layout::TensorNDHWC,
|
||||
float, cutlass::layout::TensorNDHWC,
|
||||
float, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
float
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
int8_t, cutlass::layout::TensorNDHWC,
|
||||
int8_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
int8_t, cutlass::layout::TensorNDHWC,
|
||||
int8_t, cutlass::layout::TensorNDHWC,
|
||||
int8_t, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<int8_t, float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
uint8_t, cutlass::layout::TensorNDHWC,
|
||||
uint8_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
uint8_t, cutlass::layout::TensorNDHWC,
|
||||
uint8_t, cutlass::layout::TensorNDHWC,
|
||||
int8_t, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<int8_t, float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::int4b_t, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<cutlass::int4b_t, float>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t, cutlass::layout::TensorNDHWC,
|
||||
int32_t,
|
||||
int32_t,
|
||||
NumericConverterClamp<int32_t, int32_t>
|
||||
>(manifest);
|
||||
|
||||
make_conv_fprop<
|
||||
3,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNDHWC,
|
||||
cutlass::uint4b_t, cutlass::layout::TensorNDHWC,
|
||||
float,
|
||||
int32_t,
|
||||
NumericConverterClamp<cutlass::uint4b_t, float>
|
||||
>(manifest);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,607 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines operations for all CONV operation kinds in CUTLASS Library
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
#include "cutlass/library/util.h"
|
||||
#include "library_internal.h"
|
||||
|
||||
#include "cutlass/util/reference/host/convolution.h"
|
||||
#include "cutlass/util/reference/device/convolution.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <
|
||||
Provider kProvider,
|
||||
conv::Operator ConvolutionalOperator,
|
||||
int ConvDim,
|
||||
typename ElementA_,
|
||||
typename LayoutA_,
|
||||
typename ElementB_,
|
||||
typename LayoutB_,
|
||||
typename ElementC_,
|
||||
typename LayoutC_,
|
||||
typename ElementCompute_,
|
||||
typename ElementAccumulator_ = ElementCompute_,
|
||||
typename ConvertOp_ = NumericConverter<ElementC_, ElementCompute_>,
|
||||
typename InnerProductOp_ = multiply_add<ElementAccumulator_>
|
||||
>
|
||||
struct ConvReferenceDispatcher;
|
||||
|
||||
/// Dispatcher for Conv2d (partially specialied for kConvDim == 2)
|
||||
template <
|
||||
Provider kProvider,
|
||||
conv::Operator kConvolutionalOperator,
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator,
|
||||
typename ConvertOp,
|
||||
typename InnerProductOp
|
||||
>
|
||||
struct ConvReferenceDispatcher<
|
||||
kProvider,
|
||||
kConvolutionalOperator,
|
||||
2,
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp,
|
||||
InnerProductOp> {
|
||||
|
||||
static Status dispatch(
|
||||
void const *configuration,
|
||||
ElementA *ptr_A,
|
||||
ElementB *ptr_B,
|
||||
ElementC *ptr_C,
|
||||
ElementC *ptr_D,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cudaStream_t stream = nullptr
|
||||
) {
|
||||
|
||||
Conv2dConfiguration const &config =
|
||||
*static_cast<Conv2dConfiguration const *>(configuration);
|
||||
|
||||
ConvKind const conv_kind = ConvKindMap<kConvolutionalOperator>::kId;
|
||||
|
||||
if (kProvider == Provider::kReferenceHost) {
|
||||
|
||||
cutlass::reference::host::Conv2d<
|
||||
ElementA,
|
||||
LayoutA,
|
||||
ElementB,
|
||||
LayoutB,
|
||||
ElementC ,
|
||||
LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp,
|
||||
InnerProductOp
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
config.problem_size,
|
||||
{ptr_A, config.layout_a(conv_kind)},
|
||||
{ptr_B, config.layout_b(conv_kind)},
|
||||
{ptr_C, config.layout_c(conv_kind)},
|
||||
{ptr_D, config.layout_c(conv_kind)},
|
||||
alpha,
|
||||
beta
|
||||
);
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
else if (kProvider == Provider::kReferenceDevice) {
|
||||
return cutlass::reference::device::Conv2d<
|
||||
ElementA,
|
||||
LayoutA,
|
||||
ElementB,
|
||||
LayoutB,
|
||||
ElementC,
|
||||
LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp,
|
||||
InnerProductOp
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
config.problem_size,
|
||||
{ptr_A, config.layout_a(conv_kind)},
|
||||
{ptr_B, config.layout_b(conv_kind)},
|
||||
{ptr_C, config.layout_c(conv_kind)},
|
||||
{ptr_D, config.layout_c(conv_kind)},
|
||||
alpha,
|
||||
beta,
|
||||
stream
|
||||
);
|
||||
}
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
};
|
||||
|
||||
/// Dispatcher for Conv3d (partially specialized for kConvDim == 3)
|
||||
template <
|
||||
Provider kProvider,
|
||||
conv::Operator kConvolutionalOperator,
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator,
|
||||
typename ConvertOp,
|
||||
typename InnerProductOp
|
||||
>
|
||||
struct ConvReferenceDispatcher<
|
||||
kProvider,
|
||||
kConvolutionalOperator,
|
||||
3,
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp,
|
||||
InnerProductOp> {
|
||||
|
||||
static Status dispatch(
|
||||
void const *configuration,
|
||||
ElementA *ptr_A,
|
||||
ElementB *ptr_B,
|
||||
ElementC *ptr_C,
|
||||
ElementC *ptr_D,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cudaStream_t stream = nullptr
|
||||
) {
|
||||
|
||||
Conv3dConfiguration const &config =
|
||||
*static_cast<Conv3dConfiguration const *>(configuration);
|
||||
|
||||
ConvKind const conv_kind = ConvKindMap<kConvolutionalOperator>::kId;
|
||||
|
||||
if (kProvider == Provider::kReferenceHost) {
|
||||
cutlass::reference::host::Conv3d<
|
||||
ElementA,
|
||||
LayoutA,
|
||||
ElementB,
|
||||
LayoutB,
|
||||
ElementC ,
|
||||
LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp,
|
||||
InnerProductOp
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
config.problem_size,
|
||||
{ptr_A, config.layout_a(conv_kind)},
|
||||
{ptr_B, config.layout_b(conv_kind)},
|
||||
{ptr_C, config.layout_c(conv_kind)},
|
||||
{ptr_D, config.layout_c(conv_kind)},
|
||||
alpha,
|
||||
beta
|
||||
);
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
else if (kProvider == Provider::kReferenceDevice) {
|
||||
return cutlass::reference::device::Conv3d<
|
||||
ElementA,
|
||||
LayoutA,
|
||||
ElementB,
|
||||
LayoutB,
|
||||
ElementC,
|
||||
LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp,
|
||||
InnerProductOp
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
config.problem_size,
|
||||
{ptr_A, config.layout_a(conv_kind)},
|
||||
{ptr_B, config.layout_b(conv_kind)},
|
||||
{ptr_C, config.layout_c(conv_kind)},
|
||||
{ptr_D, config.layout_c(conv_kind)},
|
||||
alpha,
|
||||
beta,
|
||||
stream
|
||||
);
|
||||
}
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <
|
||||
Provider Provider_,
|
||||
conv::Operator ConvolutionalOperator,
|
||||
int ConvDim,
|
||||
typename ElementA_,
|
||||
typename LayoutA_,
|
||||
typename ElementB_,
|
||||
typename LayoutB_,
|
||||
typename ElementC_,
|
||||
typename LayoutC_,
|
||||
typename ElementCompute_,
|
||||
typename ElementAccumulator_ = ElementCompute_,
|
||||
typename ConvertOp_ = NumericConverter<ElementC_, ElementCompute_>,
|
||||
typename InnerProductOp_ = multiply_add<ElementAccumulator_>
|
||||
>
|
||||
class ConvReferenceOperation : public Operation {
|
||||
public:
|
||||
static Provider const kProvider = Provider_;
|
||||
static conv::Operator const kConvolutionalOperator = ConvolutionalOperator;
|
||||
static int const kConvDim = ConvDim;
|
||||
|
||||
using ElementA = ElementA_;
|
||||
using LayoutA = LayoutA_;
|
||||
using ElementB = ElementB_;
|
||||
using LayoutB = LayoutB_;
|
||||
using ElementC = ElementC_;
|
||||
using LayoutC = LayoutC_;
|
||||
using ElementCompute = ElementCompute_;
|
||||
using ElementAccumulator = ElementAccumulator_;
|
||||
using ConvertOp = ConvertOp_;
|
||||
using InnerProductOp = InnerProductOp_;
|
||||
|
||||
protected:
|
||||
|
||||
/// Storage for the name string
|
||||
std::string name_;
|
||||
|
||||
///
|
||||
ConvDescription description_;
|
||||
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
ConvReferenceOperation() {
|
||||
|
||||
// Basic information
|
||||
description_.provider = kProvider;
|
||||
description_.kind = (kConvDim == 2 ? OperationKind::kConv2d : OperationKind::kConv3d);
|
||||
description_.conv_kind = ConvKindMap<kConvolutionalOperator>::kId;
|
||||
description_.conv_dim = kConvDim;
|
||||
|
||||
// Tensor description
|
||||
description_.A = make_TensorDescription<ElementA, LayoutA>();
|
||||
description_.B = make_TensorDescription<ElementB, LayoutB>();
|
||||
description_.C = make_TensorDescription<ElementC, LayoutC>();
|
||||
|
||||
// Epilogue compute and accumulator type description
|
||||
description_.element_epilogue = NumericTypeMap<ElementCompute>::kId;
|
||||
|
||||
description_.tile_description.math_instruction.element_accumulator =
|
||||
NumericTypeMap<ElementAccumulator>::kId;
|
||||
|
||||
// Iterator algorithm for convolution reference
|
||||
description_.iterator_algorithm = IteratorAlgorithmID::kNone;
|
||||
|
||||
// Compute capability for convolution reference
|
||||
description_.tile_description.minimum_compute_capability =
|
||||
(kProvider == Provider::kReferenceDevice ? 50 : 0);
|
||||
|
||||
description_.tile_description.maximum_compute_capability = 1024;
|
||||
|
||||
// Procedural name
|
||||
std::stringstream ss;
|
||||
|
||||
ss << "conv" << kConvDim << "d_" << to_string(description_.conv_kind)
|
||||
<< "_reference_" << to_string(description_.provider)
|
||||
<< "_" << to_string(description_.A.element) << to_string(description_.A.layout)
|
||||
<< "_" << to_string(description_.B.element) << to_string(description_.B.layout)
|
||||
<< "_" << to_string(description_.C.element) << to_string(description_.C.layout)
|
||||
<< "_" << to_string(description_.tile_description.math_instruction.element_accumulator);
|
||||
|
||||
name_ = ss.str();
|
||||
|
||||
description_.name = name_.c_str();
|
||||
|
||||
// Epilogue compute and accumulator type description
|
||||
description_.element_epilogue = NumericTypeMap<ElementCompute>::kId;
|
||||
|
||||
description_.tile_description.math_instruction.element_accumulator =
|
||||
NumericTypeMap<ElementAccumulator>::kId;
|
||||
}
|
||||
|
||||
/// Returns the description of the GEMM operation
|
||||
virtual OperationDescription const & description() const {
|
||||
return description_;
|
||||
}
|
||||
|
||||
virtual Status can_implement(
|
||||
void const *configuration,
|
||||
void const *arguments) const {
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
virtual uint64_t get_host_workspace_size(
|
||||
void const *configuration) const {
|
||||
|
||||
switch (kConvDim) {
|
||||
case 2:
|
||||
return sizeof(Conv2dConfiguration);
|
||||
case 3:
|
||||
return sizeof(Conv3dConfiguration);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual uint64_t get_device_workspace_size(
|
||||
void const *configuration) const {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual Status initialize(
|
||||
void const *configuration,
|
||||
void *host_workspace,
|
||||
void *device_workspace = nullptr,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
std::memcpy(host_workspace, configuration, get_host_workspace_size(configuration));
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
virtual Status run(
|
||||
void const *arguments,
|
||||
void *host_workspace,
|
||||
void *device_workspace = nullptr,
|
||||
cudaStream_t stream = nullptr) const {
|
||||
|
||||
ConvArguments const &args = *static_cast<ConvArguments const *>(arguments);
|
||||
|
||||
ElementCompute alpha;
|
||||
ElementCompute beta;
|
||||
|
||||
alpha = *static_cast<ElementCompute const *>(args.alpha);
|
||||
beta = *static_cast<ElementCompute const *>(args.beta);
|
||||
|
||||
// TODO - respect pointer mode
|
||||
|
||||
// Invoke 2D or 3D convolution
|
||||
return detail::ConvReferenceDispatcher<
|
||||
kProvider,
|
||||
kConvolutionalOperator,
|
||||
kConvDim,
|
||||
ElementA,
|
||||
LayoutA,
|
||||
ElementB,
|
||||
LayoutB,
|
||||
ElementC,
|
||||
LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp,
|
||||
InnerProductOp
|
||||
>::dispatch(
|
||||
host_workspace,
|
||||
static_cast<ElementA *>(const_cast<void *>(args.A)),
|
||||
static_cast<ElementB *>(const_cast<void *>(args.B)),
|
||||
static_cast<ElementC *>(const_cast<void *>(args.C)),
|
||||
static_cast<ElementC *>(args.D),
|
||||
alpha,
|
||||
beta,
|
||||
stream
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Constructs Fprop reference operators.
|
||||
template <
|
||||
int kConvDim,
|
||||
typename ElementA_,
|
||||
typename LayoutA_,
|
||||
typename ElementB_,
|
||||
typename LayoutB_,
|
||||
typename ElementC_,
|
||||
typename LayoutC_,
|
||||
typename ElementCompute_,
|
||||
typename ElementAccumulator_ = ElementCompute_,
|
||||
typename ConvertOp_ = NumericConverter<ElementC_, ElementCompute_>,
|
||||
typename InnerProductOp_ = multiply_add<ElementAccumulator_>
|
||||
>
|
||||
void make_conv_fprop(Manifest &manifest) {
|
||||
|
||||
manifest.append(new ConvReferenceOperation<
|
||||
Provider::kReferenceHost,
|
||||
conv::Operator::kFprop,
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>);
|
||||
|
||||
manifest.append(new ConvReferenceOperation<
|
||||
Provider::kReferenceDevice,
|
||||
conv::Operator::kFprop,
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>);
|
||||
}
|
||||
|
||||
/// Constructs Dgrad and Wgrad reference operators.
|
||||
template <
|
||||
int kConvDim,
|
||||
typename ElementA_,
|
||||
typename LayoutA_,
|
||||
typename ElementB_,
|
||||
typename LayoutB_,
|
||||
typename ElementC_,
|
||||
typename LayoutC_,
|
||||
typename ElementCompute_,
|
||||
typename ElementAccumulator_ = ElementCompute_,
|
||||
typename ConvertOp_ = NumericConverter<ElementC_, ElementCompute_>,
|
||||
typename InnerProductOp_ = multiply_add<ElementAccumulator_>
|
||||
>
|
||||
void make_conv_backwards(Manifest &manifest) {
|
||||
|
||||
manifest.append(new ConvReferenceOperation<
|
||||
Provider::kReferenceHost,
|
||||
conv::Operator::kDgrad,
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>);
|
||||
|
||||
manifest.append(new ConvReferenceOperation<
|
||||
Provider::kReferenceDevice,
|
||||
conv::Operator::kDgrad,
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>);
|
||||
|
||||
manifest.append(new ConvReferenceOperation<
|
||||
Provider::kReferenceHost,
|
||||
conv::Operator::kWgrad,
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>);
|
||||
|
||||
manifest.append(new ConvReferenceOperation<
|
||||
Provider::kReferenceDevice,
|
||||
conv::Operator::kWgrad,
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>);
|
||||
}
|
||||
|
||||
/// Six operators for the price of one.
|
||||
template <
|
||||
int kConvDim,
|
||||
typename ElementA_,
|
||||
typename LayoutA_,
|
||||
typename ElementB_,
|
||||
typename LayoutB_,
|
||||
typename ElementC_,
|
||||
typename LayoutC_,
|
||||
typename ElementCompute_,
|
||||
typename ElementAccumulator_ = ElementCompute_,
|
||||
typename ConvertOp_ = NumericConverter<ElementC_, ElementCompute_>,
|
||||
typename InnerProductOp_ = multiply_add<ElementAccumulator_>
|
||||
>
|
||||
void make_conv_all(Manifest &manifest) {
|
||||
|
||||
make_conv_fprop<
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>(manifest);
|
||||
|
||||
make_conv_backwards<
|
||||
kConvDim,
|
||||
ElementA_, LayoutA_,
|
||||
ElementB_, LayoutB_,
|
||||
ElementC_, LayoutC_,
|
||||
ElementCompute_,
|
||||
ElementAccumulator_,
|
||||
ConvertOp_,
|
||||
InnerProductOp_
|
||||
>(manifest);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace library
|
||||
} // namespace cutlass
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -37,10 +37,14 @@ namespace cutlass {
|
||||
namespace library {
|
||||
|
||||
void initialize_gemm_reference_operations(Manifest &manifest);
|
||||
void initialize_conv2d_reference_operations(Manifest &manifest);
|
||||
void initialize_conv3d_reference_operations(Manifest &manifest);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void initialize_reference_operations(Manifest &manifest) {
|
||||
initialize_conv2d_reference_operations(manifest);
|
||||
initialize_conv3d_reference_operations(manifest);
|
||||
initialize_gemm_reference_operations(manifest);
|
||||
}
|
||||
|
||||
|
||||
+168
-8
@@ -50,6 +50,7 @@ Provider_enumerants[] = {
|
||||
{"host", "reference_host", Provider::kReferenceHost},
|
||||
{"device", "reference_device", Provider::kReferenceDevice},
|
||||
{"cublas", "cuBLAS", Provider::kCUBLAS},
|
||||
{"cudnn", "cuDNN", Provider::kCUDNN},
|
||||
};
|
||||
|
||||
/// Converts a Provider enumerant to a string
|
||||
@@ -128,6 +129,9 @@ static struct {
|
||||
OperationKind_enumerants[] = {
|
||||
{"eq_gemm", "EqGemm", OperationKind::kEqGemm},
|
||||
{"gemm", "Gemm", OperationKind::kGemm},
|
||||
{"conv2d", "Conv2d", OperationKind::kConv2d},
|
||||
{"conv3d", "Conv3d", OperationKind::kConv3d},
|
||||
{"spgemm", "SparseGemm", OperationKind::kSparseGemm},
|
||||
};
|
||||
|
||||
/// Converts a Status enumerant to a string
|
||||
@@ -445,6 +449,10 @@ layout_aliases[] = {
|
||||
{LayoutTypeID::kTensorNCDHW, "ncdhw"},
|
||||
{LayoutTypeID::kTensorNHWC, "nhwc"},
|
||||
{LayoutTypeID::kTensorNDHWC, "ndhwc"},
|
||||
{LayoutTypeID::kTensorNC32HW32, "nc32hw32"},
|
||||
{LayoutTypeID::kTensorNC64HW64, "nc64hw64"},
|
||||
{LayoutTypeID::kTensorC32RSK32, "c32rsk32"},
|
||||
{LayoutTypeID::kTensorC64RSK64, "c64rsk64"},
|
||||
|
||||
{LayoutTypeID::kUnknown, "*"},
|
||||
{LayoutTypeID::kInvalid, nullptr}
|
||||
@@ -474,22 +482,46 @@ LayoutTypeID from_string<LayoutTypeID>(std::string const &str) {
|
||||
/// Gets stride rank for the layout_id (static function)
|
||||
int get_layout_stride_rank(LayoutTypeID layout_id) {
|
||||
switch (layout_id) {
|
||||
case LayoutTypeID::kColumnMajor: return cutlass::layout::ColumnMajor::kStrideRank;
|
||||
case LayoutTypeID::kRowMajor: return cutlass::layout::RowMajor::kStrideRank;
|
||||
case LayoutTypeID::kColumnMajor:
|
||||
return cutlass::layout::ColumnMajor::kStrideRank;
|
||||
case LayoutTypeID::kRowMajor:
|
||||
return cutlass::layout::RowMajor::kStrideRank;
|
||||
case LayoutTypeID::kColumnMajorInterleavedK2:
|
||||
return cutlass::layout::ColumnMajorInterleaved<2>::kStrideRank;
|
||||
case LayoutTypeID::kRowMajorInterleavedK2:
|
||||
return cutlass::layout::RowMajorInterleaved<2>::kStrideRank;
|
||||
case LayoutTypeID::kColumnMajorInterleavedK4:
|
||||
return cutlass::layout::ColumnMajorInterleaved<4>::kStrideRank;
|
||||
case LayoutTypeID::kRowMajorInterleavedK4:
|
||||
return cutlass::layout::RowMajorInterleaved<4>::kStrideRank;
|
||||
case LayoutTypeID::kColumnMajorInterleavedK16:
|
||||
return cutlass::layout::ColumnMajorInterleaved<16>::kStrideRank;
|
||||
case LayoutTypeID::kRowMajorInterleavedK16:
|
||||
return cutlass::layout::RowMajorInterleaved<16>::kStrideRank;
|
||||
case LayoutTypeID::kColumnMajorInterleavedK32:
|
||||
return cutlass::layout::ColumnMajorInterleaved<32>::kStrideRank;
|
||||
case LayoutTypeID::kRowMajorInterleavedK32:
|
||||
return cutlass::layout::RowMajorInterleaved<32>::kStrideRank;
|
||||
case LayoutTypeID::kColumnMajorInterleavedK64:
|
||||
case LayoutTypeID::kRowMajorInterleavedK64: return 1;
|
||||
return cutlass::layout::ColumnMajorInterleaved<64>::kStrideRank;
|
||||
case LayoutTypeID::kRowMajorInterleavedK64:
|
||||
return cutlass::layout::RowMajorInterleaved<64>::kStrideRank;
|
||||
case LayoutTypeID::kTensorNCHW:
|
||||
case LayoutTypeID::kTensorNHWC: return 3;
|
||||
case LayoutTypeID::kTensorNDHWC: return 4;
|
||||
default : throw std::runtime_error("Unsupported LayoutTypeID in LayoutType::get_stride_rank");
|
||||
return cutlass::layout::TensorNCHW::kStrideRank;
|
||||
case LayoutTypeID::kTensorNHWC:
|
||||
return cutlass::layout::TensorNHWC::kStrideRank;
|
||||
case LayoutTypeID::kTensorNDHWC:
|
||||
return cutlass::layout::TensorNDHWC::kStrideRank;
|
||||
case LayoutTypeID::kTensorNC32HW32:
|
||||
return cutlass::layout::TensorNCxHWx<32>::kStrideRank;
|
||||
case LayoutTypeID::kTensorNC64HW64:
|
||||
return cutlass::layout::TensorNCxHWx<64>::kStrideRank;
|
||||
case LayoutTypeID::kTensorC32RSK32:
|
||||
return cutlass::layout::TensorCxRSKx<32>::kStrideRank;
|
||||
case LayoutTypeID::kTensorC64RSK64:
|
||||
return cutlass::layout::TensorCxRSKx<64>::kStrideRank;
|
||||
default:
|
||||
throw std::runtime_error("Unsupported LayoutTypeID in LayoutType::get_stride_rank");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -624,6 +656,136 @@ SplitKMode from_string<SplitKMode>(std::string const &str) {
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static struct {
|
||||
char const *text;
|
||||
char const *pretty;
|
||||
ConvModeID enumerant;
|
||||
}
|
||||
ConvModeID_enumerants[] = {
|
||||
{"cross", "<cross>", ConvModeID::kCrossCorrelation},
|
||||
{"conv", "<conv>", ConvModeID::kConvolution},
|
||||
};
|
||||
|
||||
/// Converts a ConvModeID enumerant to a string
|
||||
char const *to_string(ConvModeID type, bool pretty) {
|
||||
|
||||
for (auto const & possible : ConvModeID_enumerants) {
|
||||
if (type == possible.enumerant) {
|
||||
if (pretty) {
|
||||
return possible.pretty;
|
||||
}
|
||||
else {
|
||||
return possible.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pretty ? "Invalid" : "invalid";
|
||||
}
|
||||
|
||||
/// Converts a ConvModeID enumerant from a string
|
||||
template <>
|
||||
ConvModeID from_string<ConvModeID>(std::string const &str) {
|
||||
|
||||
for (auto const & possible : ConvModeID_enumerants) {
|
||||
if ((str.compare(possible.text) == 0) ||
|
||||
(str.compare(possible.pretty) == 0)) {
|
||||
return possible.enumerant;
|
||||
}
|
||||
}
|
||||
|
||||
return ConvModeID::kInvalid;
|
||||
}
|
||||
|
||||
|
||||
static struct {
|
||||
char const *text;
|
||||
char const *pretty;
|
||||
IteratorAlgorithmID enumerant;
|
||||
}
|
||||
IteratorAlgorithmID_enumerants[] = {
|
||||
{"none", "<none>", IteratorAlgorithmID::kNone},
|
||||
{"analytic", "<analytic>", IteratorAlgorithmID::kAnalytic},
|
||||
{"optimized", "<optimized>", IteratorAlgorithmID::kOptimized},
|
||||
};
|
||||
|
||||
/// Converts a ConvModeID enumerant to a string
|
||||
char const *to_string(IteratorAlgorithmID type, bool pretty) {
|
||||
|
||||
for (auto const & possible : IteratorAlgorithmID_enumerants) {
|
||||
if (type == possible.enumerant) {
|
||||
if (pretty) {
|
||||
return possible.pretty;
|
||||
}
|
||||
else {
|
||||
return possible.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pretty ? "Invalid" : "invalid";
|
||||
}
|
||||
|
||||
/// Converts a ConvModeID enumerant from a string
|
||||
template <>
|
||||
IteratorAlgorithmID from_string<IteratorAlgorithmID>(std::string const &str) {
|
||||
|
||||
for (auto const & possible : IteratorAlgorithmID_enumerants) {
|
||||
if ((str.compare(possible.text) == 0) ||
|
||||
(str.compare(possible.pretty) == 0)) {
|
||||
return possible.enumerant;
|
||||
}
|
||||
}
|
||||
|
||||
return IteratorAlgorithmID::kInvalid;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static struct {
|
||||
char const *text;
|
||||
char const *pretty;
|
||||
ConvKind enumerant;
|
||||
}
|
||||
ConvKind_enumerants[] = {
|
||||
{"unknown", "<unkown>", ConvKind::kUnknown},
|
||||
{"fprop", "<fprop>", ConvKind::kFprop},
|
||||
{"dgrad", "<dgrad>", ConvKind::kDgrad},
|
||||
{"wgrad", "<wgrad>", ConvKind::kWgrad},
|
||||
};
|
||||
|
||||
/// Converts a ConvKind enumerant to a string
|
||||
char const *to_string(ConvKind type, bool pretty) {
|
||||
|
||||
for (auto const & possible : ConvKind_enumerants) {
|
||||
if (type == possible.enumerant) {
|
||||
if (pretty) {
|
||||
return possible.pretty;
|
||||
}
|
||||
else {
|
||||
return possible.text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pretty ? "Invalid" : "invalid";
|
||||
}
|
||||
|
||||
|
||||
/// Converts a ConvKind enumerant from a string
|
||||
template <>
|
||||
ConvKind from_string<ConvKind>(std::string const &str) {
|
||||
|
||||
for (auto const & possible : ConvKind_enumerants) {
|
||||
if ((str.compare(possible.text) == 0) ||
|
||||
(str.compare(possible.pretty) == 0)) {
|
||||
return possible.enumerant;
|
||||
}
|
||||
}
|
||||
|
||||
return ConvKind::kInvalid;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Lexical cast a string to a byte array. Returns true if cast is successful or false if invalid.
|
||||
bool lexical_cast(std::vector<uint8_t> &bytes, NumericTypeID type, std::string const &str) {
|
||||
int size_bytes = sizeof_bits(type) / 8;
|
||||
@@ -1224,5 +1386,3 @@ bool cast_from_double(std::vector<uint8_t> &bytes, NumericTypeID type, double sr
|
||||
} // namespace cutlass
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
@@ -34,9 +34,12 @@ set(CUTLASS_TOOLS_PROFILER_SOURCES
|
||||
src/device_allocation.cu
|
||||
src/device_context.cu
|
||||
src/cublas_helpers.cpp
|
||||
src/cudnn_helpers.cpp
|
||||
src/problem_space.cpp
|
||||
src/operation_profiler.cu
|
||||
src/gemm_operation_profiler.cu
|
||||
src/conv2d_operation_profiler.cu
|
||||
src/conv3d_operation_profiler.cu
|
||||
src/sparse_gemm_operation_profiler.cu
|
||||
)
|
||||
|
||||
@@ -58,7 +61,7 @@ set_target_properties(cutlass_profiler PROPERTIES EXPORT_NAME profiler)
|
||||
target_include_directories(
|
||||
cutlass_profiler
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/src # Source directory
|
||||
${CMAKE_CURRENT_LIST_DIR}/src
|
||||
)
|
||||
|
||||
#
|
||||
@@ -71,6 +74,7 @@ target_link_libraries(
|
||||
cutlass_lib
|
||||
cutlass_tools_util_includes
|
||||
$<$<BOOL:${CUTLASS_ENABLE_CUBLAS}>:nvidia::cublas>
|
||||
$<$<BOOL:${CUTLASS_ENABLE_CUDNN}>:nvidia::cudnn>
|
||||
cudart
|
||||
)
|
||||
|
||||
@@ -79,3 +83,16 @@ install(
|
||||
EXPORT NvidiaCutlass
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
set(CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_GEMM --operation=Gemm --providers=cutlass --verification-providers=cublas,device --junit-output=test_cutlass_profiler_gemm)
|
||||
set(CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV2D --operation=Conv2d --providers=cutlass --verification-providers=cudnn,device --junit-output=test_cutlass_profiler_conv2d)
|
||||
set(CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV3D --operation=Conv3d --providers=cutlass --verification-providers=cudnn,device,host --junit-output=test_cutlass_profiler_conv3d)
|
||||
cutlass_add_executable_tests(
|
||||
test_profiler cutlass_profiler
|
||||
DEPENDEES test_all
|
||||
TEST_COMMAND_OPTIONS
|
||||
CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_GEMM
|
||||
CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV2D
|
||||
CUTLASS_PROFILER_TEST_COMMAND_OPTIONS_CONV3D
|
||||
DISABLE_EXECUTABLE_INSTALL_RULE
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,431 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines profiling functionality for convolution
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
// CUTLASS Library includes
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/util.h"
|
||||
#include "cutlass/library/handle.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
#include "cutlass/library/singleton.h"
|
||||
|
||||
// Profiler includes
|
||||
#include "options.h"
|
||||
#include "device_context.h"
|
||||
#include "operation_profiler.h"
|
||||
#include "performance_result.h"
|
||||
#include "problem_space.h"
|
||||
#include "reduction_operation_profiler.h"
|
||||
#if CUTLASS_ENABLE_CUDNN
|
||||
#include "cudnn_helpers.h"
|
||||
#endif //#if CUTLASS_ENABLE_CUDNN
|
||||
#include "debug.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace profiler {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Abstract base class for each math function
|
||||
class Conv2dOperationProfiler : public OperationProfiler {
|
||||
public:
|
||||
|
||||
/// Problem structure obtained from problem space
|
||||
struct Conv2dProblem {
|
||||
|
||||
int64_t n, h, w, c, p, q, k, r, s;
|
||||
int64_t pad_h, pad_w;
|
||||
int64_t stride_h, stride_w;
|
||||
int64_t dilation_h, dilation_w;
|
||||
|
||||
std::vector<uint8_t> alpha;
|
||||
std::vector<uint8_t> beta;
|
||||
|
||||
library::SplitKMode split_k_mode;
|
||||
int64_t split_k_slices;
|
||||
|
||||
library::ConvModeID conv_mode;
|
||||
|
||||
library::Provider eq_gemm_provider;
|
||||
|
||||
// convolution with parallel interleaved reduction
|
||||
// convolution epilogue (alpha, beta) = (1.0, 0.0)
|
||||
// reduction epilogue (alpha, beta) = (Conv2dProblem::alpha, Conv2dProblem::beta)
|
||||
std::vector<uint8_t> alpha_one;
|
||||
std::vector<uint8_t> beta_zero;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
/// Total number of bytes loaded
|
||||
int64_t bytes(library::ConvDescription const &operation_desc) const;
|
||||
|
||||
/// Total number of flops computed
|
||||
int64_t flops(library::ConvDescription const &operation_desc) const;
|
||||
|
||||
void set_default_output_size() {
|
||||
p = ((h + pad_h - r * dilation_h) / stride_h) + 1;
|
||||
q = ((w + pad_w - s * dilation_w) / stride_w) + 1;
|
||||
}
|
||||
|
||||
// Returns equivalent gemm problem size for convolution
|
||||
cutlass::gemm::GemmCoord eq_gemm_size(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return cutlass::gemm::GemmCoord(int(n * p * q), int(k), int(r * s * c));
|
||||
case library::ConvKind::kDgrad: return cutlass::gemm::GemmCoord(int(n * h * w), int(c), int(k * r * s));
|
||||
case library::ConvKind::kWgrad: return cutlass::gemm::GemmCoord(int(k), int(r * s * c), int(n * p * q));
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns extent for tensor A
|
||||
std::vector<int> extent_a(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return {int(n), int(h), int(w), int(c)};
|
||||
case library::ConvKind::kDgrad: return {int(n), int(p), int(q), int(k)};
|
||||
case library::ConvKind::kWgrad: return {int(n), int(p), int(q), int(k)};
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns extent for tensor B
|
||||
std::vector<int> extent_b(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return {int(k), int(r), int(s), int(c)};
|
||||
case library::ConvKind::kDgrad: return {int(k), int(r), int(s), int(c)};
|
||||
case library::ConvKind::kWgrad: return {int(n), int(h), int(w), int(c)};
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns extent for tensor C
|
||||
std::vector<int> extent_c(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return {int(n), int(p), int(q), int(k)};
|
||||
case library::ConvKind::kDgrad: return {int(n), int(h), int(w), int(c)};
|
||||
case library::ConvKind::kWgrad: return {int(k), int(r), int(s), int(c)};
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns layout for equivalent gemm matrix A
|
||||
library::LayoutTypeID eq_gemm_layout_a(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return library::LayoutTypeID::kRowMajor; // TN Gemm
|
||||
case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm
|
||||
case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor; // NT Gemm
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns layout for equivalent gemm matrix B
|
||||
library::LayoutTypeID eq_gemm_layout_b(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return library::LayoutTypeID::kColumnMajor; // TN Gemm
|
||||
case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm
|
||||
case library::ConvKind::kWgrad: return library::LayoutTypeID::kRowMajor; // NT Gemm
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns layout for equivalent gemm matrix C
|
||||
library::LayoutTypeID eq_gemm_layout_c(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
// Gemm operator assumes column-major output
|
||||
case library::ConvKind::kFprop:
|
||||
case library::ConvKind::kDgrad:
|
||||
case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns leading dimenstion for equivalent gemm matrix A
|
||||
int64_t eq_gemm_lda(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k();
|
||||
case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).k();
|
||||
case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m();
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns leading dimenstion for equivalent gemm matrix B
|
||||
int64_t eq_gemm_ldb(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k();
|
||||
case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).n();
|
||||
case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).n();
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns leading dimenstion for equivalent gemm matrix C
|
||||
int64_t eq_gemm_ldc(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop:
|
||||
case library::ConvKind::kDgrad:
|
||||
case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m();
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Workspace used
|
||||
struct Conv2dWorkspace {
|
||||
|
||||
/// Conv device allocations
|
||||
DeviceAllocation *A;
|
||||
DeviceAllocation *B;
|
||||
DeviceAllocation *C;
|
||||
DeviceAllocation *Computed;
|
||||
DeviceAllocation *Reference;
|
||||
|
||||
/// Library configuration and arguments for convolution operator
|
||||
library::Conv2dConfiguration configuration;
|
||||
library::ConvArguments arguments;
|
||||
|
||||
/// Number of copies of the problem workspace which are visited sequentially during
|
||||
/// profiling to avoid camping in the last level cache.
|
||||
int problem_count;
|
||||
|
||||
/// Buffer used for the cutlass conv2d operations' host workspace
|
||||
std::vector<uint8_t> host_workspace;
|
||||
|
||||
/// Buffer used for the cutlass operations' device workspace
|
||||
DeviceAllocation device_workspace;
|
||||
|
||||
/// Library configuration and arguments for reduction operator
|
||||
library::ReductionConfiguration reduction_configuration;
|
||||
library::ReductionArguments reduction_arguments;
|
||||
|
||||
/// Buffer used for the cutlass reduction operations' host workspace
|
||||
std::vector<uint8_t> reduction_host_workspace;
|
||||
|
||||
/// Host data buffers for host reference operation
|
||||
/// host buffer for tensor
|
||||
std::vector<uint8_t> host_tensor_a;
|
||||
|
||||
/// host buffer for tensor b
|
||||
std::vector<uint8_t> host_tensor_b;
|
||||
|
||||
/// host buffer for tensor c
|
||||
std::vector<uint8_t> host_tensor_c;
|
||||
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
Conv2dWorkspace():
|
||||
A(nullptr), B(nullptr), C(nullptr), Computed(nullptr), Reference(nullptr) { }
|
||||
|
||||
// Returns stride vector for tensor A
|
||||
std::vector<int> stride_a(library::ConvKind const &conv_kind) {
|
||||
return {
|
||||
configuration.layout_a(conv_kind).stride()[0],
|
||||
configuration.layout_a(conv_kind).stride()[1],
|
||||
configuration.layout_a(conv_kind).stride()[2]
|
||||
};
|
||||
}
|
||||
|
||||
// Returns stride vector for tensor B
|
||||
std::vector<int> stride_b(library::ConvKind const &conv_kind) {
|
||||
|
||||
return {
|
||||
configuration.layout_b(conv_kind).stride()[0],
|
||||
configuration.layout_b(conv_kind).stride()[1],
|
||||
configuration.layout_b(conv_kind).stride()[2]
|
||||
};
|
||||
}
|
||||
|
||||
// Returns stride vector for tensor C
|
||||
std::vector<int> stride_c(library::ConvKind const &conv_kind) {
|
||||
|
||||
return {
|
||||
configuration.layout_c(conv_kind).stride()[0],
|
||||
configuration.layout_c(conv_kind).stride()[1],
|
||||
configuration.layout_c(conv_kind).stride()[2]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
|
||||
/// CONV problem obtained from problem space
|
||||
Conv2dProblem problem_;
|
||||
|
||||
/// Device memory allocations
|
||||
Conv2dWorkspace conv_workspace_;
|
||||
|
||||
/// CUTLASS parallel reduction operation to follow this* conv2d operation
|
||||
library::Operation const *reduction_op_;
|
||||
|
||||
public:
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
/// Ctor
|
||||
Conv2dOperationProfiler(Options const &options);
|
||||
|
||||
/// Destructor
|
||||
virtual ~Conv2dOperationProfiler();
|
||||
|
||||
/// Prints usage statement for the math function
|
||||
virtual void print_usage(std::ostream &out) const;
|
||||
|
||||
/// Prints examples
|
||||
virtual void print_examples(std::ostream &out) const;
|
||||
|
||||
/// Extracts the problem dimensions
|
||||
virtual Status initialize_configuration(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Initializes workspace
|
||||
virtual Status initialize_workspace(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Verifies CUTLASS against references
|
||||
virtual bool verify_cutlass(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Measures performance results
|
||||
virtual bool profile(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
protected:
|
||||
/// Method to profile an initialized CUTLASS operation
|
||||
virtual Status profile_cutlass_(
|
||||
double &runtime,
|
||||
Options const &options,
|
||||
library::Operation const *operation,
|
||||
void *arguments,
|
||||
void *host_workspace,
|
||||
void *device_workspace);
|
||||
|
||||
|
||||
/// Initialize reduction problem dimenstions and library::Operation
|
||||
bool initialize_reduction_configuration_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Initializes the performance result
|
||||
void initialize_result_(
|
||||
PerformanceResult &result,
|
||||
Options const &options,
|
||||
library::ConvDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space);
|
||||
|
||||
/// Verifies CUTLASS against host reference
|
||||
bool verify_with_host_reference_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Verifies CUTLASS against device reference
|
||||
bool verify_with_device_reference_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
#if CUTLASS_ENABLE_CUDNN
|
||||
|
||||
/// Verifies CUTLASS against cudnn reference
|
||||
bool verify_with_cudnn_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
#endif //#if CUTLASS_ENABLE_CUDNN
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,441 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines profiling functionality for convolution
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
// CUTLASS Library includes
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/util.h"
|
||||
#include "cutlass/library/handle.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
#include "cutlass/library/singleton.h"
|
||||
|
||||
// Profiler includes
|
||||
#include "options.h"
|
||||
#include "device_context.h"
|
||||
#include "operation_profiler.h"
|
||||
#include "performance_result.h"
|
||||
#include "problem_space.h"
|
||||
#include "reduction_operation_profiler.h"
|
||||
#if CUTLASS_ENABLE_CUDNN
|
||||
#include "cudnn_helpers.h"
|
||||
#endif //#if CUTLASS_ENABLE_CUDNN
|
||||
#include "debug.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace profiler {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Abstract base class for each math function
|
||||
class Conv3dOperationProfiler : public OperationProfiler {
|
||||
public:
|
||||
|
||||
/// Problem structure obtained from problem space
|
||||
struct Conv3dProblem {
|
||||
|
||||
int64_t n, d, h, w, c, z, p, q, k, t, r, s;
|
||||
int64_t pad_d, pad_h, pad_w;
|
||||
int64_t stride_d, stride_h, stride_w;
|
||||
int64_t dilation_d, dilation_h, dilation_w;
|
||||
|
||||
std::vector<uint8_t> alpha;
|
||||
std::vector<uint8_t> beta;
|
||||
|
||||
library::SplitKMode split_k_mode;
|
||||
int64_t split_k_slices;
|
||||
|
||||
library::ConvModeID conv_mode;
|
||||
|
||||
library::Provider eq_gemm_provider;
|
||||
|
||||
// convolution with parallel interleaved reduction
|
||||
// convolution epilogue (alpha, beta) = (1.0, 0.0)
|
||||
// reduction epilogue (alpha, beta) = (Conv3dProblem::alpha, Conv3dProblem::beta)
|
||||
std::vector<uint8_t> alpha_one;
|
||||
std::vector<uint8_t> beta_zero;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
/// Total number of bytes loaded
|
||||
int64_t bytes(library::ConvDescription const &operation_desc) const;
|
||||
|
||||
/// Total number of flops computed
|
||||
int64_t flops(library::ConvDescription const &operation_desc) const;
|
||||
|
||||
/// Infers output size from theinput size, padding, stride, and dilation
|
||||
void set_default_output_size() {
|
||||
z = ((d + pad_d - t * dilation_d) / stride_d) + 1;
|
||||
p = ((h + pad_h - r * dilation_h) / stride_h) + 1;
|
||||
q = ((w + pad_w - s * dilation_w) / stride_w) + 1;
|
||||
}
|
||||
|
||||
// Returns equivalent gemm problem size for convolution
|
||||
cutlass::gemm::GemmCoord eq_gemm_size(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return cutlass::gemm::GemmCoord(int(n * z * p * q), int(k), int(t * r * s * c));
|
||||
case library::ConvKind::kDgrad: return cutlass::gemm::GemmCoord(int(n * d * h * w), int(c), int(t * r * s * k));
|
||||
case library::ConvKind::kWgrad: return cutlass::gemm::GemmCoord(int(k), int(t * r * s * c), int(n * z * p * q));
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns extent for tensor A
|
||||
std::vector<int> extent_a(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return {int(n), int(d), int(h), int(w), int(c)};
|
||||
case library::ConvKind::kDgrad: return {int(n), int(z), int(p), int(q), int(k)};
|
||||
case library::ConvKind::kWgrad: return {int(n), int(z), int(p), int(q), int(k)};
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns extent for tensor B
|
||||
std::vector<int> extent_b(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return {int(k), int(t), int(r), int(s), int(c)};
|
||||
case library::ConvKind::kDgrad: return {int(k), int(t), int(r), int(s), int(c)};
|
||||
case library::ConvKind::kWgrad: return {int(n), int(d), int(h), int(w), int(c)};
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns extent for tensor C
|
||||
std::vector<int> extent_c(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return {int(n), int(z), int(p), int(q), int(k)};
|
||||
case library::ConvKind::kDgrad: return {int(n), int(d), int(h), int(w), int(c)};
|
||||
case library::ConvKind::kWgrad: return {int(k), int(t), int(r), int(s), int(c)};
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns layout for equivalent gemm matrix A
|
||||
library::LayoutTypeID eq_gemm_layout_a(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return library::LayoutTypeID::kRowMajor; // TN Gemm
|
||||
case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm
|
||||
case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor; // NT Gemm
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns layout for equivalent gemm matrix B
|
||||
library::LayoutTypeID eq_gemm_layout_b(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return library::LayoutTypeID::kColumnMajor; // TN Gemm
|
||||
case library::ConvKind::kDgrad: return library::LayoutTypeID::kRowMajor; // TT Gemm
|
||||
case library::ConvKind::kWgrad: return library::LayoutTypeID::kRowMajor; // NT Gemm
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns layout for equivalent gemm matrix C
|
||||
library::LayoutTypeID eq_gemm_layout_c(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
// Gemm operator assumes column-major output
|
||||
case library::ConvKind::kFprop:
|
||||
case library::ConvKind::kDgrad:
|
||||
case library::ConvKind::kWgrad: return library::LayoutTypeID::kColumnMajor;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns leading dimenstion for equivalent gemm matrix A
|
||||
int64_t eq_gemm_lda(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k();
|
||||
case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).k();
|
||||
case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m();
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns leading dimenstion for equivalent gemm matrix B
|
||||
int64_t eq_gemm_ldb(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop: return eq_gemm_size(conv_kind).k();
|
||||
case library::ConvKind::kDgrad: return eq_gemm_size(conv_kind).n();
|
||||
case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).n();
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns leading dimenstion for equivalent gemm matrix C
|
||||
int64_t eq_gemm_ldc(library::ConvKind const &conv_kind) const {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop:
|
||||
case library::ConvKind::kDgrad:
|
||||
case library::ConvKind::kWgrad: return eq_gemm_size(conv_kind).m();
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Workspace used
|
||||
struct Conv2dWorkspace {
|
||||
|
||||
/// Conv device allocations
|
||||
DeviceAllocation *A;
|
||||
DeviceAllocation *B;
|
||||
DeviceAllocation *C;
|
||||
DeviceAllocation *Computed;
|
||||
DeviceAllocation *Reference;
|
||||
|
||||
/// Library configuration and arguments for convolution operator
|
||||
library::Conv3dConfiguration configuration;
|
||||
library::ConvArguments arguments;
|
||||
|
||||
/// Number of copies of the problem workspace which are visited sequentially during
|
||||
/// profiling to avoid camping in the last level cache.
|
||||
int problem_count;
|
||||
|
||||
/// Buffer used for the cutlass conv2d operations' host workspace
|
||||
std::vector<uint8_t> host_workspace;
|
||||
|
||||
/// Buffer used for the cutlass operations' device workspace
|
||||
DeviceAllocation device_workspace;
|
||||
|
||||
/// Library configuration and arguments for reduction operator
|
||||
library::ReductionConfiguration reduction_configuration;
|
||||
library::ReductionArguments reduction_arguments;
|
||||
|
||||
/// Buffer used for the cutlass reduction operations' host workspace
|
||||
std::vector<uint8_t> reduction_host_workspace;
|
||||
|
||||
/// Host data buffers for host reference operation
|
||||
/// host buffer for tensor
|
||||
std::vector<uint8_t> host_tensor_a;
|
||||
|
||||
/// host buffer for tensor b
|
||||
std::vector<uint8_t> host_tensor_b;
|
||||
|
||||
/// host buffer for tensor c
|
||||
std::vector<uint8_t> host_tensor_c;
|
||||
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
Conv2dWorkspace():
|
||||
A(nullptr), B(nullptr), C(nullptr), Computed(nullptr), Reference(nullptr) { }
|
||||
|
||||
// Returns stride vector for tensor A
|
||||
std::vector<int> stride_a(library::ConvKind const &conv_kind) {
|
||||
return {
|
||||
configuration.layout_a(conv_kind).stride()[0],
|
||||
configuration.layout_a(conv_kind).stride()[1],
|
||||
configuration.layout_a(conv_kind).stride()[2],
|
||||
configuration.layout_a(conv_kind).stride()[3]
|
||||
};
|
||||
}
|
||||
|
||||
// Returns stride vector for tensor B
|
||||
std::vector<int> stride_b(library::ConvKind const &conv_kind) {
|
||||
|
||||
return {
|
||||
configuration.layout_b(conv_kind).stride()[0],
|
||||
configuration.layout_b(conv_kind).stride()[1],
|
||||
configuration.layout_b(conv_kind).stride()[2],
|
||||
configuration.layout_b(conv_kind).stride()[3]
|
||||
};
|
||||
}
|
||||
|
||||
// Returns stride vector for tensor C
|
||||
std::vector<int> stride_c(library::ConvKind const &conv_kind) {
|
||||
|
||||
return {
|
||||
configuration.layout_c(conv_kind).stride()[0],
|
||||
configuration.layout_c(conv_kind).stride()[1],
|
||||
configuration.layout_c(conv_kind).stride()[2],
|
||||
configuration.layout_c(conv_kind).stride()[3]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
|
||||
/// CONV problem obtained from problem space
|
||||
Conv3dProblem problem_;
|
||||
|
||||
/// Device memory allocations
|
||||
Conv2dWorkspace conv_workspace_;
|
||||
|
||||
/// CUTLASS parallel reduction operation to follow this* conv2d operation
|
||||
library::Operation const *reduction_op_;
|
||||
|
||||
public:
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
/// Ctor
|
||||
Conv3dOperationProfiler(Options const &options);
|
||||
|
||||
/// Destructor
|
||||
virtual ~Conv3dOperationProfiler();
|
||||
|
||||
/// Prints usage statement for the math function
|
||||
virtual void print_usage(std::ostream &out) const;
|
||||
|
||||
/// Prints examples
|
||||
virtual void print_examples(std::ostream &out) const;
|
||||
|
||||
/// Extracts the problem dimensions
|
||||
virtual Status initialize_configuration(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Initializes workspace
|
||||
virtual Status initialize_workspace(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Verifies CUTLASS against references
|
||||
virtual bool verify_cutlass(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Measures performance results
|
||||
virtual bool profile(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
protected:
|
||||
|
||||
/// Updates the arguments structure for the CUTLASS operator based on
|
||||
/// the problem index.
|
||||
void set_cutlass_operator_arguments_(int problem_idx = 0);
|
||||
|
||||
/// Method to profile an initialized CUTLASS operation
|
||||
virtual Status profile_cutlass_(
|
||||
double &runtime,
|
||||
Options const &options,
|
||||
library::Operation const *operation,
|
||||
void *arguments,
|
||||
void *host_workspace,
|
||||
void *device_workspace);
|
||||
|
||||
/// Initialize reduction problem dimenstions and library::Operation
|
||||
bool initialize_reduction_configuration_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Initializes the performance result
|
||||
void initialize_result_(
|
||||
PerformanceResult &result,
|
||||
Options const &options,
|
||||
library::ConvDescription const &operation_desc,
|
||||
ProblemSpace const &problem_space);
|
||||
|
||||
/// Verifies CUTLASS against host reference
|
||||
bool verify_with_host_reference_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Verifies CUTLASS against device reference
|
||||
bool verify_with_device_reference_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
#if CUTLASS_ENABLE_CUDNN
|
||||
|
||||
/// Verifies CUTLASS against cudnn reference
|
||||
bool verify_with_cudnn_(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
#endif //#if CUTLASS_ENABLE_CUDNN
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,485 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Helper functions for mapping CUTLASS concepts to cuDNN.
|
||||
*/
|
||||
#if CUTLASS_ENABLE_CUDNN
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "cudnn_helpers.h"
|
||||
|
||||
namespace cutlass {
|
||||
namespace profiler {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Converts a cuDNN status to cutlass::Status
|
||||
Status get_cutlass_status(cudnnStatus_t cudnn_status) {
|
||||
|
||||
if (cudnn_status == CUDNN_STATUS_SUCCESS) {
|
||||
return Status::kSuccess;
|
||||
}
|
||||
else if (cudnn_status == CUDNN_STATUS_INVALID_VALUE) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
if (cudnn_status == CUDNN_STATUS_NOT_SUPPORTED) {
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
return Status::kErrorInternal;
|
||||
}
|
||||
|
||||
/// Converts a cuDNN status to cutlass::profiler::Disposition
|
||||
Disposition get_cutlass_disposition(cudnnStatus_t cudnn_status) {
|
||||
|
||||
if (cudnn_status == CUDNN_STATUS_INVALID_VALUE) {
|
||||
return Disposition::kInvalidProblem;
|
||||
}
|
||||
else if (cudnn_status == CUDNN_STATUS_NOT_SUPPORTED) {
|
||||
return Disposition::kNotSupported;
|
||||
}
|
||||
return Disposition::kFailed;
|
||||
}
|
||||
|
||||
/// Checks cudnnStatus_t converts to cutlas status and returns if Status::kSuccess o.w. throws exception
|
||||
Status checkCudnnErr(cudnnStatus_t cudnn_status) {
|
||||
Status cutlass_status = get_cutlass_status(cudnn_status);
|
||||
if(cutlass_status != Status::kSuccess) {
|
||||
throw std::runtime_error("checkCudnnErr failed");
|
||||
}
|
||||
return cutlass_status;
|
||||
}
|
||||
|
||||
/// Maps a CUTLASS conv mode to a cuDNN cudnnConvolutionMode_t
|
||||
bool get_cudnn_conv_mode(cudnnConvolutionMode_t &cudnn_conv_mode, conv::Mode conv_mode) {
|
||||
switch (conv_mode) {
|
||||
case conv::Mode::kCrossCorrelation:
|
||||
cudnn_conv_mode = CUDNN_CROSS_CORRELATION;
|
||||
return true;
|
||||
case conv::Mode::kConvolution:
|
||||
cudnn_conv_mode = CUDNN_CONVOLUTION;
|
||||
return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Maps a CUTLASS tensor layout to a cuDNN cudnnTensorFormat_t
|
||||
bool get_cudnn_layout(cudnnTensorFormat_t &cudnn_layout, library::LayoutTypeID layout) {
|
||||
switch (layout) {
|
||||
// cudnn uses the same enum for TensorNC*HW along nDim (ConvDescription::conv_dim)
|
||||
case library::LayoutTypeID::kTensorNCHW:
|
||||
case library::LayoutTypeID::kTensorNCDHW:
|
||||
cudnn_layout = CUDNN_TENSOR_NCHW;
|
||||
return true;
|
||||
case library::LayoutTypeID::kTensorNHWC:
|
||||
case library::LayoutTypeID::kTensorNDHWC:
|
||||
cudnn_layout = CUDNN_TENSOR_NHWC;
|
||||
return true;
|
||||
default: break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Maps a CUTLASS numeric type to a cuDNN cudnnDataType_t
|
||||
bool get_cudnn_datatype(cudnnDataType_t &cudnn_element_type, library::NumericTypeID element_type) {
|
||||
switch (element_type) {
|
||||
case library::NumericTypeID::kF16:
|
||||
cudnn_element_type = CUDNN_DATA_HALF;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kF32:
|
||||
cudnn_element_type = CUDNN_DATA_FLOAT;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kF64:
|
||||
cudnn_element_type = CUDNN_DATA_DOUBLE;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kS2:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kS4:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kS8:
|
||||
cudnn_element_type = CUDNN_DATA_INT8;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kS16:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kS32:
|
||||
cudnn_element_type = CUDNN_DATA_INT32;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kS64:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kU2:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kU4:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kU8:
|
||||
cudnn_element_type = CUDNN_DATA_UINT8;
|
||||
return true;
|
||||
|
||||
case library::NumericTypeID::kU16:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kU32:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kU64:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kB1:
|
||||
break;
|
||||
|
||||
case library::NumericTypeID::kInvalid:
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Maps CUTLASS math OpcodeClassID and MathOperationID to cuDNN math_type
|
||||
bool get_cudnn_mathtype(cudnnMathType_t &cudnn_math_type, library::ConvDescription const &conv_desc) {
|
||||
|
||||
switch (conv_desc.tile_description.math_instruction.opcode_class) {
|
||||
|
||||
case library::OpcodeClassID::kTensorOp:
|
||||
{
|
||||
cudnn_math_type = CUDNN_TENSOR_OP_MATH;
|
||||
|
||||
library::MathOperationID math_op = conv_desc.tile_description.math_instruction.math_operation;
|
||||
|
||||
// Allow conversion on input data type for fast math operations
|
||||
if (math_op == library::MathOperationID::kMultiplyAddFastF16 ||
|
||||
math_op == library::MathOperationID::kMultiplyAddFastBF16)
|
||||
{
|
||||
cudnn_math_type = CUDNN_TENSOR_OP_MATH_ALLOW_CONVERSION;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
case library::OpcodeClassID::kSimt:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Cudnn compute type seems to be hardcoded to float (To handle a possible cudnn issue)
|
||||
float cast_cudnn_compute_type_to_float(library::NumericTypeID type, void const * src) {
|
||||
|
||||
switch (type) {
|
||||
case library::NumericTypeID::kF16:
|
||||
{
|
||||
return float(*(static_cast<half_t const*>(src)));
|
||||
}
|
||||
case library::NumericTypeID::kF32:
|
||||
{
|
||||
return float(*(static_cast<float const*>(src)));
|
||||
}
|
||||
case library::NumericTypeID::kS32:
|
||||
{
|
||||
return float(*(static_cast<int const*>(src)));
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Data type handled in cast_compute_type_to_float");
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Returns a status if cuDNN can satisfy a particular Conv2d description
|
||||
Status cudnn_satisfies(
|
||||
library::ConvDescription const &desc,
|
||||
library::Conv2dConfiguration const &configuration) {
|
||||
|
||||
auto const &a_tensor = desc.A;
|
||||
auto const &b_tensor = desc.B;
|
||||
auto const &c_tensor = desc.C;
|
||||
auto const &math_instruction = desc.tile_description.math_instruction;
|
||||
|
||||
if(a_tensor.element != b_tensor.element) {
|
||||
return Status::kErrorInvalidDataType;
|
||||
}
|
||||
|
||||
//////////////////////// Convolution output dimensions p and q ///////////////////////
|
||||
// Cutlass convolutions support arbitrary output dimensions and not constriant by //
|
||||
// input, filter, padding, striding, dilation sizes. //
|
||||
// cuDNN sets the output dimensions (p, q) using following equations: //
|
||||
// //
|
||||
// output = div_up(input + 2 * pad - ((filter - 1) * dilation + 1) + 1, stride) //
|
||||
// where; div_up(a, b) : (a - 1)/b + 1 //
|
||||
// //
|
||||
// Before launching cudnn verification or profiling check that output p and q //
|
||||
// dimensions are cuDNN compliant. //
|
||||
// //
|
||||
// If user sets output p and q which do not follow above constraints, cutlass conv, //
|
||||
// host reference, device reference can run. However, cudnn convolution returns //
|
||||
// "Invalid problem" //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// check conv output dimension p for cudnn
|
||||
int cudnn_output_p =
|
||||
(
|
||||
(
|
||||
configuration.problem_size.H +
|
||||
2 * configuration.problem_size.pad_h -
|
||||
((configuration.problem_size.R - 1) *
|
||||
configuration.problem_size.dilation_h + 1)
|
||||
) /
|
||||
(configuration.problem_size.stride_h)
|
||||
+ 1
|
||||
);
|
||||
|
||||
if (cudnn_output_p != configuration.problem_size.P) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
// check conv output dimension q for cudnn
|
||||
int cudnn_output_q =
|
||||
(
|
||||
(
|
||||
configuration.problem_size.W +
|
||||
2 * configuration.problem_size.pad_w -
|
||||
((configuration.problem_size.S - 1) *
|
||||
configuration.problem_size.dilation_w + 1)
|
||||
) /
|
||||
(configuration.problem_size.stride_w)
|
||||
+ 1
|
||||
);
|
||||
|
||||
if (cudnn_output_q != configuration.problem_size.Q) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// conv operator with input=FP16, accumulator=FP32, output=FP32 datatype
|
||||
if (a_tensor.element == library::NumericTypeID::kF16 &&
|
||||
b_tensor.element == library::NumericTypeID::kF16 &&
|
||||
math_instruction.element_accumulator == library::NumericTypeID::kF32 &&
|
||||
c_tensor.element == library::NumericTypeID::kF32
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kBF16 ||
|
||||
b_tensor.element == library::NumericTypeID::kBF16 ||
|
||||
c_tensor.element == library::NumericTypeID::kBF16
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
// TF32 input not supported in cuDNN
|
||||
if (a_tensor.element == library::NumericTypeID::kTF32 ||
|
||||
b_tensor.element == library::NumericTypeID::kTF32 ||
|
||||
c_tensor.element == library::NumericTypeID::kTF32
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kS8 ||
|
||||
b_tensor.element == library::NumericTypeID::kS8 ||
|
||||
c_tensor.element == library::NumericTypeID::kS8
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kU8 ||
|
||||
b_tensor.element == library::NumericTypeID::kU8 ||
|
||||
c_tensor.element == library::NumericTypeID::kU8
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kS4 ||
|
||||
b_tensor.element == library::NumericTypeID::kS4 ||
|
||||
c_tensor.element == library::NumericTypeID::kS4
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kU4 ||
|
||||
b_tensor.element == library::NumericTypeID::kU4 ||
|
||||
c_tensor.element == library::NumericTypeID::kU4
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns a status if cuDNN can satisfy a particular Conv3d description
|
||||
Status cudnn_satisfies(
|
||||
library::ConvDescription const &desc,
|
||||
library::Conv3dConfiguration const &configuration) {
|
||||
|
||||
auto const &a_tensor = desc.A;
|
||||
auto const &b_tensor = desc.B;
|
||||
auto const &c_tensor = desc.C;
|
||||
auto const &math_instruction = desc.tile_description.math_instruction;
|
||||
|
||||
if(a_tensor.element != b_tensor.element) {
|
||||
return Status::kErrorInvalidDataType;
|
||||
}
|
||||
|
||||
//////////////////////// Convolution output dimensions p and q ///////////////////////
|
||||
// Cutlass convolutions support arbitrary output dimensions and not constriant by //
|
||||
// input, filter, padding, striding, dilation sizes. //
|
||||
// cuDNN sets the output dimensions (p, q) using following equations: //
|
||||
// //
|
||||
// output = div_up(input + 2 * pad - ((filter - 1) * dilation + 1) + 1, stride) //
|
||||
// where; div_up(a, b) : (a - 1)/b + 1 //
|
||||
// //
|
||||
// Before launching cudnn verification or profiling check that output p and q //
|
||||
// dimensions are cuDNN compliant. //
|
||||
// //
|
||||
// If user sets output p and q which do not follow above constraints, cutlass conv, //
|
||||
// host reference, device reference can run. However, cudnn convolution returns //
|
||||
// "Invalid problem" //
|
||||
// //
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// check conv output dimension z for cudnn
|
||||
int cudnn_output_z =
|
||||
(
|
||||
(
|
||||
configuration.problem_size.D +
|
||||
2 * configuration.problem_size.pad_d -
|
||||
((configuration.problem_size.T - 1) *
|
||||
configuration.problem_size.dilation_d + 1)
|
||||
) /
|
||||
(configuration.problem_size.stride_d)
|
||||
+ 1
|
||||
);
|
||||
|
||||
if (cudnn_output_z != configuration.problem_size.Z) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
// check conv output dimension p for cudnn
|
||||
int cudnn_output_p =
|
||||
(
|
||||
(
|
||||
configuration.problem_size.H +
|
||||
2 * configuration.problem_size.pad_h -
|
||||
((configuration.problem_size.R - 1) *
|
||||
configuration.problem_size.dilation_h + 1)
|
||||
) /
|
||||
(configuration.problem_size.stride_h)
|
||||
+ 1
|
||||
);
|
||||
|
||||
if (cudnn_output_p != configuration.problem_size.P) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
|
||||
// check conv output dimension q for cudnn
|
||||
int cudnn_output_q =
|
||||
(
|
||||
(
|
||||
configuration.problem_size.W +
|
||||
2 * configuration.problem_size.pad_w -
|
||||
((configuration.problem_size.S - 1) *
|
||||
configuration.problem_size.dilation_w + 1)
|
||||
) /
|
||||
(configuration.problem_size.stride_w)
|
||||
+ 1
|
||||
);
|
||||
|
||||
if (cudnn_output_q != configuration.problem_size.Q) {
|
||||
return Status::kErrorInvalidProblem;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// conv operator with input, accumulator, output datatype of (hss) are not supported
|
||||
// in cuDNN
|
||||
if (a_tensor.element == library::NumericTypeID::kF16 &&
|
||||
b_tensor.element == library::NumericTypeID::kF16 &&
|
||||
math_instruction.element_accumulator == library::NumericTypeID::kF32 &&
|
||||
c_tensor.element == library::NumericTypeID::kF32
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kBF16 ||
|
||||
b_tensor.element == library::NumericTypeID::kBF16 ||
|
||||
c_tensor.element == library::NumericTypeID::kBF16
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kTF32 ||
|
||||
b_tensor.element == library::NumericTypeID::kTF32 ||
|
||||
c_tensor.element == library::NumericTypeID::kTF32
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
if (a_tensor.element == library::NumericTypeID::kS8 ||
|
||||
b_tensor.element == library::NumericTypeID::kS8 ||
|
||||
c_tensor.element == library::NumericTypeID::kS8
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
// S4 not supported in cuDNN
|
||||
if (a_tensor.element == library::NumericTypeID::kS4 ||
|
||||
b_tensor.element == library::NumericTypeID::kS4 ||
|
||||
c_tensor.element == library::NumericTypeID::kS4
|
||||
) {
|
||||
|
||||
return Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
return Status::kSuccess;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,584 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Helper functions for mapping CUTLASS concepts to cuDNN.
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#if CUTLASS_ENABLE_CUDNN
|
||||
#include <cuda_runtime.h>
|
||||
#include <cudnn.h>
|
||||
#include <iostream>
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/util/device_memory.h"
|
||||
#include "cutlass/library/library.h"
|
||||
#include "enumerated_types.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace profiler {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Converts a cuDNN status to cutlass::Status
|
||||
Status get_cutlass_status(cudnnStatus_t cudnn_status);
|
||||
|
||||
/// Converts a cuDNN status to cutlass::profiler::Disposition
|
||||
Disposition get_cutlass_disposition(cudnnStatus_t cudnn_status);
|
||||
|
||||
/// Checks cudnnStatus_t converts to cutlas status and returns if Status::kSuccess o.w. throws exception
|
||||
Status checkCudnnErr(cudnnStatus_t cudnn_status);
|
||||
|
||||
/// Maps a CUTLASS conv mode to a cuDNN conv mode enumeration
|
||||
bool get_cudnn_conv_mode(cudnnConvolutionMode_t &cudnn_conv_mode, conv::Mode conv_mode);
|
||||
|
||||
/// Maps a CUTLASS layout type to a cuDNN data type enumeration
|
||||
bool get_cudnn_layout(cudnnTensorFormat_t &cudnn_layout, library::LayoutTypeID layout);
|
||||
|
||||
/// Maps a CUTLASS numeric type to a cuDNN data type enumeration
|
||||
bool get_cudnn_datatype(cudnnDataType_t &cudnn_element_type, library::NumericTypeID element_type);
|
||||
|
||||
/// Maps CUTLASS math OpcodeClassID and MathOperationID to cuDNN math_type
|
||||
bool get_cudnn_mathtype(cudnnMathType_t &cudnn_math_type, library::ConvDescription const &conv_desc);
|
||||
|
||||
/// Returns a status if cudnn can satisfy a particular Conv2d description
|
||||
Status cudnn_satisfies(library::ConvDescription const &desc, library::Conv2dConfiguration const &configuration);
|
||||
|
||||
/// Returns a status if cudnn can satisfy a particular Conv3d description
|
||||
Status cudnn_satisfies(library::ConvDescription const &desc, library::Conv3dConfiguration const &configuration);
|
||||
|
||||
/// Cudnn compute type seems to be hardcoded to float (To handle a possible cudnn issue)
|
||||
float cast_cudnn_compute_type_to_float(library::NumericTypeID type, void const * src);
|
||||
|
||||
|
||||
/// This is a helper class to create cudnnHandle_t automatically on CudnnCreate object creation and
|
||||
/// to destroy cudnnHandle_t on CudnnCreate object destruction.
|
||||
/// Additionaly, it provides implicit cast from CudnnCreate's object to cudnnHandle_t's object
|
||||
class CudnnCreate {
|
||||
private:
|
||||
cudnnHandle_t handle;
|
||||
cudnnStatus_t status;
|
||||
|
||||
public:
|
||||
CudnnCreate() {
|
||||
status = cudnnCreate(&handle);
|
||||
}
|
||||
|
||||
~CudnnCreate() {
|
||||
cudnnDestroy(handle);
|
||||
}
|
||||
|
||||
/// Implicit cast CudnnCreate object to cudnnHandle_t
|
||||
operator cudnnHandle_t() const { return handle; }
|
||||
|
||||
/// returns cudnnStatus_t for handle creation
|
||||
cudnnStatus_t get_cudnn_create_status() { return status; }
|
||||
};
|
||||
|
||||
|
||||
namespace detail {
|
||||
|
||||
/// Dispatcher to cudnn convolution operators
|
||||
struct cudnnConvDispatcher {
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
//library::Conv2dConfiguration configuration;
|
||||
library::ConvArguments arguments;
|
||||
library::ConvKind conv_kind;
|
||||
|
||||
// cudnn-specific data structures to fill cudnn API call arguments
|
||||
// cudnn activation, filter, and output descriptors
|
||||
cudnnTensorDescriptor_t activation_desc;
|
||||
cudnnFilterDescriptor_t filter_desc;
|
||||
cudnnTensorDescriptor_t output_desc;
|
||||
cudnnConvolutionDescriptor_t conv_desc;
|
||||
|
||||
// cudnn datatypes
|
||||
cudnnDataType_t data_type_activation;
|
||||
cudnnDataType_t data_type_filter;
|
||||
cudnnDataType_t data_type_output;
|
||||
|
||||
// cudnn layouts
|
||||
cudnnTensorFormat_t layout_activation;
|
||||
cudnnTensorFormat_t layout_filter;
|
||||
cudnnTensorFormat_t layout_output;
|
||||
|
||||
// cudnn convolution mode
|
||||
cudnnConvolutionMode_t conv_mode;
|
||||
|
||||
// cudnn math type (tensorop, tensorop with conversion, simt)
|
||||
cudnnMathType_t math_type;
|
||||
|
||||
// cudnn compute data type
|
||||
cudnnDataType_t compute_type;
|
||||
|
||||
// cudnn compute type seems to be hardcoded to float (to handle a possible a cudnn issue)
|
||||
float alpha;
|
||||
float beta;
|
||||
|
||||
// cudnn workspace
|
||||
size_t workspace_size_in_bytes = 0;
|
||||
cutlass::device_memory::allocation<char> workspace;
|
||||
|
||||
// select cudnn's implicit gemm precomputed algorithm with tensor operations
|
||||
static cudnnConvolutionFwdAlgo_t const fprop_algo = CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM;
|
||||
static cudnnConvolutionBwdDataAlgo_t const dgrad_algo = CUDNN_CONVOLUTION_BWD_DATA_ALGO_1;
|
||||
static cudnnConvolutionBwdFilterAlgo_t const wgrad_algo = CUDNN_CONVOLUTION_BWD_FILTER_ALGO_1;
|
||||
|
||||
Status status;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
// TODO: unify ctor cudnnConvDispatcher for conv2d and conv3d by unifying Conv2dConfigration
|
||||
|
||||
// ctor for conv2d
|
||||
cudnnConvDispatcher(
|
||||
library::ConvDescription const &op_desc,
|
||||
library::Conv2dConfiguration configuration,
|
||||
library::ConvArguments arguments_,
|
||||
cudnnHandle_t handle
|
||||
):
|
||||
//configuration(configuration_),
|
||||
arguments(arguments_),
|
||||
conv_kind(op_desc.conv_kind),
|
||||
status(Status::kSuccess) {
|
||||
|
||||
bool good = true;
|
||||
|
||||
// Get cudnn datatype, layout, and convolution mode from library::ConvDescription
|
||||
good = (good && get_cudnn_datatype(data_type_activation, op_desc.A.element));
|
||||
good = (good && get_cudnn_datatype(data_type_filter, op_desc.B.element));
|
||||
good = (good && get_cudnn_datatype(data_type_output, op_desc.C.element));
|
||||
good = (good && get_cudnn_layout(layout_activation, op_desc.A.layout));
|
||||
good = (good && get_cudnn_layout(layout_filter, op_desc.B.layout));
|
||||
good = (good && get_cudnn_layout(layout_output, op_desc.C.layout));
|
||||
good = (good && get_cudnn_conv_mode(conv_mode, configuration.problem_size.mode));
|
||||
// Get cudnn mathtype (cudnnMathType_t)
|
||||
good = (good && get_cudnn_mathtype(math_type, op_desc));
|
||||
good = (good && get_cudnn_datatype(
|
||||
compute_type,
|
||||
op_desc.tile_description.math_instruction.element_accumulator));
|
||||
// Check cutlass Conv2d description has equivalent operator in cudnn
|
||||
if (!good) {
|
||||
status = Status::kErrorNotSupported;
|
||||
return;
|
||||
}
|
||||
// cudnn compute type seems to be hardcoded to float (to handle a possible a cudnn issue)
|
||||
alpha = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.alpha);
|
||||
beta = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.beta);
|
||||
|
||||
// Create convolution descriptor object
|
||||
status = get_cutlass_status(cudnnCreateConvolutionDescriptor(&conv_desc));
|
||||
|
||||
// Configure convolution operator
|
||||
std::vector<int> padding {configuration.problem_size.pad_h, configuration.problem_size.pad_w};
|
||||
std::vector<int> stride {configuration.problem_size.stride_h, configuration.problem_size.stride_w};
|
||||
std::vector<int> dilation {configuration.problem_size.dilation_h, configuration.problem_size.dilation_w};
|
||||
|
||||
status = get_cutlass_status(
|
||||
cudnnSetConvolutionNdDescriptor(
|
||||
conv_desc,
|
||||
op_desc.conv_dim,
|
||||
padding.data(),
|
||||
stride.data(),
|
||||
dilation.data(),
|
||||
conv_mode,
|
||||
compute_type
|
||||
));
|
||||
|
||||
// Set groups
|
||||
status = get_cutlass_status(cudnnSetConvolutionGroupCount(conv_desc, configuration.problem_size.groups));
|
||||
|
||||
// Create activation, filter, and output descriptor objects
|
||||
status = get_cutlass_status(cudnnCreateTensorDescriptor(&activation_desc));
|
||||
status = get_cutlass_status(cudnnCreateFilterDescriptor(&filter_desc));
|
||||
status = get_cutlass_status(cudnnCreateTensorDescriptor(&output_desc));
|
||||
|
||||
// Set activation, filter, and output descriptor
|
||||
status = get_cutlass_status(
|
||||
cudnnSetTensor4dDescriptor(
|
||||
activation_desc,
|
||||
layout_activation,
|
||||
data_type_activation,
|
||||
configuration.problem_size.N,
|
||||
configuration.problem_size.C,
|
||||
configuration.problem_size.H,
|
||||
configuration.problem_size.W
|
||||
));
|
||||
|
||||
status = get_cutlass_status(
|
||||
cudnnSetFilter4dDescriptor(
|
||||
filter_desc,
|
||||
data_type_filter,
|
||||
layout_filter,
|
||||
configuration.problem_size.K,
|
||||
configuration.problem_size.C,
|
||||
configuration.problem_size.R,
|
||||
configuration.problem_size.S
|
||||
));
|
||||
|
||||
status = get_cutlass_status(
|
||||
cudnnSetTensor4dDescriptor(
|
||||
output_desc,
|
||||
layout_output,
|
||||
data_type_output,
|
||||
configuration.problem_size.N,
|
||||
configuration.problem_size.K,
|
||||
configuration.problem_size.P,
|
||||
configuration.problem_size.Q
|
||||
));
|
||||
|
||||
// Set math instruction to tensor op
|
||||
status = get_cutlass_status(
|
||||
cudnnSetConvolutionMathType(conv_desc, math_type));
|
||||
|
||||
// Initialize workspace
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop:
|
||||
status = get_cutlass_status(
|
||||
cudnnGetConvolutionForwardWorkspaceSize(
|
||||
handle,
|
||||
activation_desc,
|
||||
filter_desc,
|
||||
conv_desc,
|
||||
output_desc,
|
||||
fprop_algo,
|
||||
&workspace_size_in_bytes
|
||||
)); break;
|
||||
case library::ConvKind::kDgrad:
|
||||
status = get_cutlass_status(
|
||||
cudnnGetConvolutionBackwardDataWorkspaceSize(
|
||||
handle,
|
||||
filter_desc,
|
||||
output_desc,
|
||||
conv_desc,
|
||||
activation_desc,
|
||||
dgrad_algo,
|
||||
&workspace_size_in_bytes
|
||||
)); break;
|
||||
case library::ConvKind::kWgrad:
|
||||
status = get_cutlass_status(
|
||||
cudnnGetConvolutionBackwardFilterWorkspaceSize(
|
||||
handle,
|
||||
activation_desc,
|
||||
output_desc,
|
||||
conv_desc,
|
||||
filter_desc,
|
||||
wgrad_algo,
|
||||
&workspace_size_in_bytes
|
||||
)); break;
|
||||
|
||||
}
|
||||
|
||||
workspace = cutlass::device_memory::allocation<char>(workspace_size_in_bytes);
|
||||
}
|
||||
|
||||
|
||||
// ctor for conv3d
|
||||
cudnnConvDispatcher(
|
||||
library::ConvDescription const &op_desc,
|
||||
library::Conv3dConfiguration configuration,
|
||||
library::ConvArguments arguments_,
|
||||
cudnnHandle_t handle
|
||||
):
|
||||
//configuration(configuration_),
|
||||
arguments(arguments_),
|
||||
conv_kind(op_desc.conv_kind),
|
||||
status(Status::kSuccess) {
|
||||
|
||||
bool good = true;
|
||||
|
||||
// Get cudnn datatype, layout, and convolution mode from library::ConvDescription
|
||||
good = (good && get_cudnn_datatype(data_type_activation, op_desc.A.element));
|
||||
good = (good && get_cudnn_datatype(data_type_filter, op_desc.B.element));
|
||||
good = (good && get_cudnn_datatype(data_type_output, op_desc.C.element));
|
||||
|
||||
good = (good && get_cudnn_layout(layout_activation, op_desc.A.layout));
|
||||
good = (good && get_cudnn_layout(layout_filter, op_desc.B.layout));
|
||||
good = (good && get_cudnn_layout(layout_output, op_desc.C.layout));
|
||||
|
||||
good = (good && get_cudnn_conv_mode(conv_mode, configuration.problem_size.mode));
|
||||
|
||||
// cudnn compute type seems to be hardcoded to float (to handle a possible a cudnn issue)
|
||||
alpha = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.alpha);
|
||||
beta = cast_cudnn_compute_type_to_float(op_desc.element_epilogue, arguments.beta);
|
||||
|
||||
good = (good && get_cudnn_datatype(
|
||||
compute_type,
|
||||
op_desc.tile_description.math_instruction.element_accumulator));
|
||||
|
||||
// Check cutlass Conv2d description has equivalent operator in cudnn
|
||||
if (!good) {
|
||||
status = Status::kErrorNotSupported;
|
||||
}
|
||||
|
||||
// Create convolution descriptor object
|
||||
status = get_cutlass_status(cudnnCreateConvolutionDescriptor(&conv_desc));
|
||||
|
||||
// Configure convolution operator
|
||||
std::vector<int> padding {configuration.problem_size.pad_d, configuration.problem_size.pad_h, configuration.problem_size.pad_w};
|
||||
std::vector<int> stride {configuration.problem_size.stride_d, configuration.problem_size.stride_h, configuration.problem_size.stride_w};
|
||||
std::vector<int> dilation {configuration.problem_size.dilation_d, configuration.problem_size.dilation_h, configuration.problem_size.dilation_w};
|
||||
|
||||
status = get_cutlass_status(
|
||||
cudnnSetConvolutionNdDescriptor(
|
||||
conv_desc,
|
||||
op_desc.conv_dim,
|
||||
padding.data(),
|
||||
stride.data(),
|
||||
dilation.data(),
|
||||
conv_mode,
|
||||
compute_type
|
||||
));
|
||||
|
||||
// Set groups
|
||||
status = get_cutlass_status(cudnnSetConvolutionGroupCount(conv_desc, configuration.problem_size.groups));
|
||||
|
||||
// Create activation, filter, and output descriptor objects
|
||||
status = get_cutlass_status(cudnnCreateTensorDescriptor(&activation_desc));
|
||||
status = get_cutlass_status(cudnnCreateFilterDescriptor(&filter_desc));
|
||||
status = get_cutlass_status(cudnnCreateTensorDescriptor(&output_desc));
|
||||
|
||||
// Set activation descriptor
|
||||
std::vector<int> activation_extent {
|
||||
configuration.problem_size.N,
|
||||
configuration.problem_size.C,
|
||||
configuration.problem_size.D,
|
||||
configuration.problem_size.H,
|
||||
configuration.problem_size.W
|
||||
};
|
||||
|
||||
std::vector<int> activation_stride {
|
||||
configuration.layout_activations.stride()[3],
|
||||
1,
|
||||
configuration.layout_activations.stride()[2],
|
||||
configuration.layout_activations.stride()[1],
|
||||
configuration.layout_activations.stride()[0]
|
||||
};
|
||||
|
||||
status = get_cutlass_status(
|
||||
cudnnSetTensorNdDescriptor(
|
||||
activation_desc,
|
||||
data_type_activation,
|
||||
op_desc.conv_dim + 2,
|
||||
activation_extent.data(),
|
||||
activation_stride.data()
|
||||
));
|
||||
|
||||
// Set filter descriptor
|
||||
std::vector<int> filter_extent {
|
||||
configuration.problem_size.K,
|
||||
configuration.problem_size.C,
|
||||
configuration.problem_size.T,
|
||||
configuration.problem_size.R,
|
||||
configuration.problem_size.S
|
||||
};
|
||||
|
||||
std::vector<int> filter_stride {
|
||||
configuration.layout_filters.stride()[3],
|
||||
1,
|
||||
configuration.layout_filters.stride()[2],
|
||||
configuration.layout_filters.stride()[1],
|
||||
configuration.layout_filters.stride()[0]
|
||||
};
|
||||
|
||||
status = get_cutlass_status(
|
||||
cudnnSetFilterNdDescriptor(
|
||||
filter_desc,
|
||||
data_type_filter,
|
||||
layout_filter,
|
||||
op_desc.conv_dim + 2,
|
||||
filter_extent.data()
|
||||
));
|
||||
|
||||
|
||||
// Set output descriptor
|
||||
std::vector<int> output_extent {
|
||||
configuration.problem_size.N,
|
||||
configuration.problem_size.K,
|
||||
configuration.problem_size.Z,
|
||||
configuration.problem_size.P,
|
||||
configuration.problem_size.Q
|
||||
};
|
||||
|
||||
std::vector<int> output_stride {
|
||||
configuration.layout_output.stride()[3],
|
||||
1,
|
||||
configuration.layout_output.stride()[2],
|
||||
configuration.layout_output.stride()[1],
|
||||
configuration.layout_output.stride()[0]
|
||||
};
|
||||
|
||||
status = get_cutlass_status(
|
||||
cudnnSetTensorNdDescriptor(
|
||||
output_desc,
|
||||
data_type_output,
|
||||
op_desc.conv_dim + 2,
|
||||
output_extent.data(),
|
||||
output_stride.data()
|
||||
));
|
||||
|
||||
// Set math instruction to tensor op
|
||||
status = get_cutlass_status(
|
||||
cudnnSetConvolutionMathType(conv_desc, math_type));
|
||||
|
||||
// Initialize workspace
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop:
|
||||
status = get_cutlass_status(
|
||||
cudnnGetConvolutionForwardWorkspaceSize(
|
||||
handle,
|
||||
activation_desc,
|
||||
filter_desc,
|
||||
conv_desc,
|
||||
output_desc,
|
||||
fprop_algo,
|
||||
&workspace_size_in_bytes
|
||||
)); break;
|
||||
case library::ConvKind::kDgrad:
|
||||
status = get_cutlass_status(
|
||||
cudnnGetConvolutionBackwardDataWorkspaceSize(
|
||||
handle,
|
||||
filter_desc,
|
||||
output_desc,
|
||||
conv_desc,
|
||||
activation_desc,
|
||||
dgrad_algo,
|
||||
&workspace_size_in_bytes
|
||||
)); break;
|
||||
case library::ConvKind::kWgrad:
|
||||
status = get_cutlass_status(
|
||||
cudnnGetConvolutionBackwardFilterWorkspaceSize(
|
||||
handle,
|
||||
activation_desc,
|
||||
output_desc,
|
||||
conv_desc,
|
||||
filter_desc,
|
||||
wgrad_algo,
|
||||
&workspace_size_in_bytes
|
||||
)); break;
|
||||
|
||||
}
|
||||
|
||||
workspace = cutlass::device_memory::allocation<char>(workspace_size_in_bytes);
|
||||
}
|
||||
|
||||
/// Executes Conv2d operater from cudnn library
|
||||
cudnnStatus_t operator()(cudnnHandle_t handle) {
|
||||
|
||||
switch (conv_kind) {
|
||||
case library::ConvKind::kFprop:
|
||||
return cudnnConvolutionForward(
|
||||
handle,
|
||||
&alpha,
|
||||
activation_desc,
|
||||
activation(),
|
||||
filter_desc,
|
||||
filter(),
|
||||
conv_desc,
|
||||
fprop_algo,
|
||||
workspace.get(),
|
||||
workspace_size_in_bytes,
|
||||
&beta,
|
||||
output_desc,
|
||||
arguments.D
|
||||
);
|
||||
case library::ConvKind::kDgrad:
|
||||
return cudnnConvolutionBackwardData(
|
||||
handle,
|
||||
&alpha,
|
||||
filter_desc,
|
||||
filter(),
|
||||
output_desc,
|
||||
output(),
|
||||
conv_desc,
|
||||
dgrad_algo,
|
||||
workspace.get(),
|
||||
workspace_size_in_bytes,
|
||||
&beta,
|
||||
activation_desc,
|
||||
arguments.D
|
||||
);
|
||||
case library::ConvKind::kWgrad:
|
||||
return cudnnConvolutionBackwardFilter(
|
||||
handle,
|
||||
&alpha,
|
||||
activation_desc,
|
||||
activation(),
|
||||
output_desc,
|
||||
output(),
|
||||
conv_desc,
|
||||
wgrad_algo,
|
||||
workspace.get(),
|
||||
workspace_size_in_bytes,
|
||||
&beta,
|
||||
filter_desc,
|
||||
arguments.D
|
||||
);
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns Actviation Tensor
|
||||
void const * activation() const {
|
||||
switch(conv_kind) {
|
||||
case library::ConvKind::kFprop : return arguments.A;
|
||||
case library::ConvKind::kDgrad : return arguments.C;
|
||||
case library::ConvKind::kWgrad : return arguments.B;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns Filter Tensor
|
||||
void const *filter() const {
|
||||
switch(conv_kind) {
|
||||
case library::ConvKind::kFprop : return arguments.B;
|
||||
case library::ConvKind::kDgrad : return arguments.B;
|
||||
case library::ConvKind::kWgrad : return arguments.C;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns Output Tensor
|
||||
void const *output() const {
|
||||
switch(conv_kind) {
|
||||
case library::ConvKind::kFprop : return arguments.C;
|
||||
case library::ConvKind::kDgrad : return arguments.A;
|
||||
case library::ConvKind::kWgrad : return arguments.A;
|
||||
default : throw std::runtime_error("Invalid Conv Operator (fprop, dgrad, wgrad)");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif //#if CUTLASS_ENABLE_CUDNN
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
@@ -32,6 +32,8 @@
|
||||
// Profiler includes
|
||||
#include "cutlass_profiler.h"
|
||||
#include "gemm_operation_profiler.h"
|
||||
#include "conv2d_operation_profiler.h"
|
||||
#include "conv3d_operation_profiler.h"
|
||||
#include "sparse_gemm_operation_profiler.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -50,6 +52,10 @@ CutlassProfiler::CutlassProfiler(
|
||||
|
||||
operation_profilers_.emplace_back(new SparseGemmOperationProfiler(options));
|
||||
|
||||
operation_profilers_.emplace_back(new Conv2dOperationProfiler(options));
|
||||
|
||||
operation_profilers_.emplace_back(new Conv3dOperationProfiler(options));
|
||||
|
||||
}
|
||||
|
||||
CutlassProfiler::~CutlassProfiler() {
|
||||
@@ -159,6 +165,8 @@ void CutlassProfiler::print_usage_(std::ostream &out) {
|
||||
|
||||
out << "\n\nFor details about a particular function, specify the function name with --help.\n\nExample:\n\n"
|
||||
<< " $ cutlass_profiler --operation=Gemm --help\n\n"
|
||||
<< " $ cutlass_profiler --operation=Conv3d --help\n\n"
|
||||
<< " $ cutlass_profiler --operation=Conv2d --help\n\n"
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,18 @@ std::vector<int> DeviceAllocation::get_packed_layout(
|
||||
case library::LayoutTypeID::kTensorNDHWC:
|
||||
stride = get_packed_layout_stride<cutlass::layout::TensorNDHWC>(extent);
|
||||
break;
|
||||
|
||||
case library::LayoutTypeID::kTensorNC32HW32:
|
||||
stride = get_packed_layout_stride<cutlass::layout::TensorNCxHWx<32>>(extent);
|
||||
break;
|
||||
case library::LayoutTypeID::kTensorNC64HW64:
|
||||
stride = get_packed_layout_stride<cutlass::layout::TensorNCxHWx<64>>(extent);
|
||||
break;
|
||||
case library::LayoutTypeID::kTensorC32RSK32:
|
||||
stride = get_packed_layout_stride<cutlass::layout::TensorCxRSKx<32>>(extent);
|
||||
break;
|
||||
case library::LayoutTypeID::kTensorC64RSK64:
|
||||
stride = get_packed_layout_stride<cutlass::layout::TensorCxRSKx<64>>(extent);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -247,6 +258,18 @@ size_t DeviceAllocation::construct_layout(
|
||||
case library::LayoutTypeID::kTensorNDHWC:
|
||||
return construct_layout_<cutlass::layout::TensorNDHWC>(bytes, layout_id, extent, stride);
|
||||
|
||||
case library::LayoutTypeID::kTensorNC32HW32:
|
||||
return construct_layout_<cutlass::layout::TensorNCxHWx<32>>(bytes, layout_id, extent, stride);
|
||||
|
||||
case library::LayoutTypeID::kTensorNC64HW64:
|
||||
return construct_layout_<cutlass::layout::TensorNCxHWx<64>>(bytes, layout_id, extent, stride);
|
||||
|
||||
case library::LayoutTypeID::kTensorC32RSK32:
|
||||
return construct_layout_<cutlass::layout::TensorCxRSKx<32>>(bytes, layout_id, extent, stride);
|
||||
|
||||
case library::LayoutTypeID::kTensorC64RSK64:
|
||||
return construct_layout_<cutlass::layout::TensorCxRSKx<64>>(bytes, layout_id, extent, stride);
|
||||
|
||||
default: break;
|
||||
}
|
||||
|
||||
@@ -1362,6 +1385,18 @@ static void write_tensor_csv_static_type(
|
||||
case library::LayoutTypeID::kTensorNDHWC:
|
||||
write_tensor_csv_static_tensor_view<T, layout::TensorNDHWC>(out, allocation);
|
||||
break;
|
||||
case library::LayoutTypeID::kTensorNC32HW32:
|
||||
write_tensor_csv_static_tensor_view<T, layout::TensorNCxHWx<32>>(out, allocation);
|
||||
break;
|
||||
case library::LayoutTypeID::kTensorNC64HW64:
|
||||
write_tensor_csv_static_tensor_view<T, layout::TensorNCxHWx<64>>(out, allocation);
|
||||
break;
|
||||
case library::LayoutTypeID::kTensorC32RSK32:
|
||||
write_tensor_csv_static_tensor_view<T, layout::TensorCxRSKx<32>>(out, allocation);
|
||||
break;
|
||||
case library::LayoutTypeID::kTensorC64RSK64:
|
||||
write_tensor_csv_static_tensor_view<T, layout::TensorCxRSKx<64>>(out, allocation);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unhandled layout");
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ int OperationProfiler::profile_all(
|
||||
ProblemSpace::Iterator problem_it = problem_space.begin();
|
||||
ProblemSpace::Iterator problem_end = problem_space.end();
|
||||
|
||||
bool continue_profiling = true;
|
||||
bool continue_profiling = true, internal_error = false;
|
||||
|
||||
// For each problem in problem space
|
||||
for (; continue_profiling && problem_it != problem_end; ++problem_it) {
|
||||
@@ -302,7 +302,8 @@ int OperationProfiler::profile_all(
|
||||
|
||||
if (status == Status::kErrorInternal) {
|
||||
// Stop profiling if there was an internal error
|
||||
return false;
|
||||
internal_error = true;
|
||||
break;
|
||||
}
|
||||
else if (status != Status::kSuccess) {
|
||||
// If the workspace could not be initialized for any other reason, continue to
|
||||
@@ -322,7 +323,8 @@ int OperationProfiler::profile_all(
|
||||
|
||||
if (status == Status::kErrorInternal) {
|
||||
// Stop profiling if there was an internal error
|
||||
return false;
|
||||
internal_error = true;
|
||||
break;
|
||||
}
|
||||
else if (status != Status::kSuccess) {
|
||||
// If the workspace could not be initialized for any other reason, continue to
|
||||
@@ -336,8 +338,9 @@ int OperationProfiler::profile_all(
|
||||
//
|
||||
|
||||
// B. Verify CUTLASS
|
||||
if (continue_profiling) {
|
||||
|
||||
|
||||
if (continue_profiling && options.profiling.provider_enabled(library::Provider::kCUTLASS)) {
|
||||
|
||||
continue_profiling = this->verify_cutlass(
|
||||
options,
|
||||
report,
|
||||
@@ -368,6 +371,7 @@ int OperationProfiler::profile_all(
|
||||
//
|
||||
// D. Profile
|
||||
//
|
||||
|
||||
if (continue_profiling && options.profiling.enabled) {
|
||||
|
||||
continue_profiling = this->profile(
|
||||
@@ -392,10 +396,7 @@ int OperationProfiler::profile_all(
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Emit report
|
||||
report.close();
|
||||
|
||||
return 0;
|
||||
return internal_error ? 1 : 0;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -401,6 +401,7 @@ Options::Profiling::Profiling(cutlass::CommandLine const &cmdline) {
|
||||
else {
|
||||
providers.push_back(library::Provider::kCUTLASS);
|
||||
providers.push_back(library::Provider::kCUBLAS);
|
||||
providers.push_back(library::Provider::kCUDNN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,8 +429,8 @@ void Options::Profiling::print_usage(std::ostream &out) const {
|
||||
|
||||
<< " --providers=<providers> "
|
||||
<< " List of providers to be profiled for performance. (default: '*')" << end_of_line
|
||||
<< " Gemm providers {cutlass*"
|
||||
<< "}" << end_of_line
|
||||
<< " Gemm providers {cutlass*, cublas*}" << end_of_line
|
||||
<< " Conv2d providers {cutlass*, cudnn*}"
|
||||
<< "\n\n";
|
||||
|
||||
}
|
||||
@@ -502,6 +503,7 @@ Options::Verification::Verification(cutlass::CommandLine const &cmdline) {
|
||||
else {
|
||||
providers.push_back(library::Provider::kCUBLAS);
|
||||
providers.push_back(library::Provider::kReferenceDevice);
|
||||
providers.push_back(library::Provider::kCUDNN);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,6 +531,7 @@ void Options::Verification::print_usage(std::ostream &out) const {
|
||||
<< " --verification-providers=<providers> "
|
||||
<< " List of providers used to verify result. (default: '*')" << end_of_line
|
||||
<< " Gemm verification-providers {cublas*}" << end_of_line
|
||||
<< " Conv2d verification-providers {cudnn*, device*, host}"
|
||||
<< "\n\n";
|
||||
}
|
||||
|
||||
@@ -570,6 +573,7 @@ Options::Report::Report(cutlass::CommandLine const &cmdline) {
|
||||
|
||||
cmdline.get_cmd_line_argument("append", append, false);
|
||||
cmdline.get_cmd_line_argument("output", output_path);
|
||||
cmdline.get_cmd_line_argument("junit-output", junit_output_path);
|
||||
|
||||
if (cmdline.check_cmd_line_flag("tags")) {
|
||||
cmdline.get_cmd_line_argument_pairs("tags", pivot_tags);
|
||||
@@ -591,6 +595,9 @@ void Options::Report::print_usage(std::ostream &out) const {
|
||||
<< " --output=<path> "
|
||||
<< " Path to output file for machine readable results. Operation kind and '.csv' is appended.\n\n"
|
||||
|
||||
<< " --junit-output=<path> "
|
||||
<< " Path to junit output file for result reporting. Operation kind and '.junit.xml' is appended.\n\n"
|
||||
|
||||
<< " --report-not-run=<bool> "
|
||||
<< " If true, reports the status of all kernels including those that" << end_of_line
|
||||
<< " do not satisfy the given arguments.\n\n"
|
||||
@@ -608,6 +615,7 @@ void Options::Report::print_options(std::ostream &out, int indent) const {
|
||||
out
|
||||
<< indent_str(indent) << "append: " << append << "\n"
|
||||
<< indent_str(indent) << "output: " << output_path << "\n"
|
||||
<< indent_str(indent) << "junit-output: " << junit_output_path << "\n"
|
||||
<< indent_str(indent) << "report_not_run: " << report_not_run << "\n"
|
||||
<< indent_str(indent) << "tags:\n";
|
||||
|
||||
|
||||
@@ -218,6 +218,9 @@ public:
|
||||
/// Path to a file containing results
|
||||
std::string output_path;
|
||||
|
||||
/// Path to a file containing junit xml results
|
||||
std::string junit_output_path;
|
||||
|
||||
/// Sequence of tags to attach to each result
|
||||
std::vector<std::pair<std::string, std::string>> pivot_tags;
|
||||
|
||||
|
||||
@@ -69,11 +69,15 @@ PerformanceReport::PerformanceReport(
|
||||
options_(options), argument_names_(argument_names), problem_index_(0), good_(true), op_kind_(op_kind) {
|
||||
|
||||
// Strip '.csv' if present
|
||||
std::string base_path = options_.report.output_path.substr(
|
||||
0, options_.report.output_path.rfind(".csv"));
|
||||
|
||||
std::string base_path = options_.report.output_path;
|
||||
base_path = base_path.substr(0, base_path.rfind(".csv"));
|
||||
op_file_name_ = base_path + "." + to_string(op_kind_) + ".csv";
|
||||
|
||||
base_path = options_.report.junit_output_path;
|
||||
base_path = base_path.substr(0, base_path.rfind(".xml"));
|
||||
base_path = base_path.substr(0, base_path.rfind(".junit"));
|
||||
op_junit_file_name_ = base_path + "." + to_string(op_kind_) + ".junit.xml";
|
||||
|
||||
//
|
||||
// Open output file for operation of PerformanceReport::op_kind
|
||||
//
|
||||
@@ -108,6 +112,21 @@ PerformanceReport::PerformanceReport(
|
||||
print_csv_header_(output_file_) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (!options_.report.junit_output_path.empty()) {
|
||||
|
||||
junit_output_file_.open(op_junit_file_name_);
|
||||
|
||||
if (!junit_output_file_.good()) {
|
||||
|
||||
std::cerr << "Could not open junit output file at path '"
|
||||
<< options_.report.junit_output_path << "'" << std::endl;
|
||||
|
||||
good_ = false;
|
||||
}
|
||||
|
||||
print_junit_header_(junit_output_file_);
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceReport::next_problem() {
|
||||
@@ -123,6 +142,10 @@ void PerformanceReport::append_result(PerformanceResult result) {
|
||||
print_result_pretty_(std::cout, result) << std::flush;
|
||||
}
|
||||
|
||||
if (junit_output_file_.is_open()) {
|
||||
print_junit_result_(junit_output_file_, result);
|
||||
}
|
||||
|
||||
if (output_file_.is_open()) {
|
||||
print_result_csv_(output_file_, result) << std::endl;
|
||||
}
|
||||
@@ -143,7 +166,7 @@ void PerformanceReport::append_results(PerformanceResultVector const &results) {
|
||||
}
|
||||
}
|
||||
|
||||
void PerformanceReport::close() {
|
||||
PerformanceReport::~PerformanceReport() {
|
||||
|
||||
//
|
||||
// Output results to stdout if they were not written to a file already.
|
||||
@@ -161,7 +184,17 @@ void PerformanceReport::close() {
|
||||
}
|
||||
}
|
||||
else if (output_file_.is_open() && options_.report.verbose) {
|
||||
std::cout << "\n\nWrote results to '" << op_file_name_ << "'" << std::endl;
|
||||
std::cout << "\nWrote results to '" << op_file_name_ << "'" << std::endl;
|
||||
}
|
||||
|
||||
if (output_file_.is_open()) {
|
||||
output_file_.close();
|
||||
}
|
||||
|
||||
if (junit_output_file_.is_open()) {
|
||||
print_junit_footer_(junit_output_file_);
|
||||
junit_output_file_.close();
|
||||
std::cout << "\nWrote jUnit results to '" << op_junit_file_name_ << "'" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,7 +212,8 @@ static const char *disposition_status_color(Disposition disposition) {
|
||||
/// Prints the result in human readable form
|
||||
std::ostream & PerformanceReport::print_result_pretty_(
|
||||
std::ostream &out,
|
||||
PerformanceResult const &result) {
|
||||
PerformanceResult const &result,
|
||||
bool use_shell_coloring) {
|
||||
|
||||
out << "=============================\n"
|
||||
<< " Problem ID: " << result.problem_index << "\n";
|
||||
@@ -196,14 +230,20 @@ std::ostream & PerformanceReport::print_result_pretty_(
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
std::string shell_color_bright = use_shell_coloring ? SHELL_COLOR_BRIGHT() : "";
|
||||
std::string shell_color_end = use_shell_coloring ? SHELL_COLOR_END() : "";
|
||||
auto _disposition_status_color = [&](Disposition d) -> const char * {
|
||||
return use_shell_coloring ? disposition_status_color(d) : "";
|
||||
};
|
||||
|
||||
out
|
||||
<< "\n"
|
||||
<< " Provider: " << SHELL_COLOR_BRIGHT() << library::to_string(result.provider, true) << SHELL_COLOR_END() << "\n"
|
||||
<< " OperationKind: " << SHELL_COLOR_BRIGHT() << library::to_string(result.op_kind) << SHELL_COLOR_END() << "\n"
|
||||
<< " Provider: " << shell_color_bright << library::to_string(result.provider, true) << shell_color_end << "\n"
|
||||
<< " OperationKind: " << shell_color_bright << library::to_string(result.op_kind) << shell_color_end << "\n"
|
||||
<< " Operation: " << result.operation_name << "\n\n"
|
||||
<< " Status: " << SHELL_COLOR_BRIGHT() << library::to_string(result.status, true) << SHELL_COLOR_END() << "\n"
|
||||
<< " Verification: " << SHELL_COLOR_BRIGHT() << (options_.verification.enabled ? "ON":"OFF") << SHELL_COLOR_END() << "\n"
|
||||
<< " Disposition: " << disposition_status_color(result.disposition) << to_string(result.disposition, true) << SHELL_COLOR_END() << "\n\n";
|
||||
<< " Status: " << shell_color_bright << library::to_string(result.status, true) << shell_color_end << "\n"
|
||||
<< " Verification: " << shell_color_bright << (options_.verification.enabled ? "ON":"OFF") << shell_color_end << "\n"
|
||||
<< " Disposition: " << _disposition_status_color(result.disposition) << to_string(result.disposition, true) << shell_color_end << "\n\n";
|
||||
|
||||
// Display individual verification results for each verification-provider
|
||||
if (options_.verification.enabled) {
|
||||
@@ -263,10 +303,6 @@ std::ostream & PerformanceReport::print_csv_header_(
|
||||
<< ",OperationKind,Operation,Disposition,Status";
|
||||
|
||||
for (auto const &arg_name : argument_names_) {
|
||||
// Operand E is internal to the sparse kernel
|
||||
if (arg_name.compare("E") == 0)
|
||||
continue;
|
||||
|
||||
out << "," << arg_name;
|
||||
}
|
||||
|
||||
@@ -327,6 +363,112 @@ std::ostream & PerformanceReport::print_result_csv_(
|
||||
return out;
|
||||
}
|
||||
|
||||
std::ostream & PerformanceReport::print_junit_header_(std::ostream &out) {
|
||||
|
||||
out << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << std::endl;
|
||||
out << "<testsuite name=\"cutlass_profiler\">" << std::endl;
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::string escape_xml_special_chars(const std::string& src) {
|
||||
std::stringstream dst;
|
||||
for (char ch : src) {
|
||||
switch (ch) {
|
||||
case '&': dst << "&"; break;
|
||||
case '\'': dst << "'"; break;
|
||||
case '"': dst << """; break;
|
||||
case '<': dst << "<"; break;
|
||||
case '>': dst << ">"; break;
|
||||
default: dst << ch; break;
|
||||
}
|
||||
}
|
||||
return dst.str();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::ostream & print_junit_result_property_(std::ostream & os, const std::string & name, const T & property) {
|
||||
return os << " <property name=\"" << name << "\" value=\"" << property << "\" />" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream & PerformanceReport::print_junit_result_(std::ostream &out, PerformanceResult const &result) {
|
||||
|
||||
out << " " << "<testcase name=\"";
|
||||
|
||||
std::string delim = "";
|
||||
|
||||
// Pivot tags
|
||||
for (auto const & tag : options_.report.pivot_tags) {
|
||||
out << delim << tag.second; delim = "_";
|
||||
}
|
||||
|
||||
out << delim << to_string(result.op_kind); delim = "_";
|
||||
out << delim << result.operation_name;
|
||||
|
||||
for (auto const & arg : result.arguments) {
|
||||
out << delim << arg.second;
|
||||
}
|
||||
|
||||
out << "\" ";
|
||||
|
||||
bool skipped = false, failed = false, error = false;
|
||||
|
||||
switch (result.disposition) {
|
||||
case Disposition::kNotRun:
|
||||
case Disposition::kNotSupported:
|
||||
skipped = true;
|
||||
break;
|
||||
case Disposition::kPassed:
|
||||
case Disposition::kNotVerified:
|
||||
break;
|
||||
case Disposition::kFailed:
|
||||
case Disposition::kIncorrect:
|
||||
failed = true;
|
||||
break;
|
||||
case Disposition::kInvalidProblem:
|
||||
case Disposition::kInvalid:
|
||||
error = true;
|
||||
break;
|
||||
};
|
||||
|
||||
if (skipped) {
|
||||
out << "status=\"notrun\"";
|
||||
} else {
|
||||
out << "status=\"run\"";
|
||||
}
|
||||
|
||||
out << ">" << std::endl;
|
||||
|
||||
if (failed) {
|
||||
out << " <failure message=\"" << to_string(result.disposition) << "\" />" << std::endl;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
out << " <error message=\"" << to_string(result.disposition) << "\" />" << std::endl;
|
||||
}
|
||||
|
||||
out << " <system-out><![CDATA[" << std::endl;
|
||||
std::stringstream ss;
|
||||
print_result_pretty_(ss, result, false);
|
||||
out << escape_xml_special_chars(ss.str()) << std::endl;
|
||||
out << " ]]></system-out>" << std::endl;
|
||||
|
||||
out << " </testcase>" << std::endl;
|
||||
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
std::ostream & PerformanceReport::print_junit_footer_(std::ostream &out) {
|
||||
|
||||
out << "</testsuite>" << std::endl;
|
||||
return out;
|
||||
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
|
||||
@@ -59,6 +59,12 @@ private:
|
||||
/// Output file containing results
|
||||
std::ofstream output_file_;
|
||||
|
||||
/// Operation file name containing junit performance report of op_kind
|
||||
std::string op_junit_file_name_;
|
||||
|
||||
/// Output file containing junit results
|
||||
std::ofstream junit_output_file_;
|
||||
|
||||
/// Flag indicating the performance report is valid
|
||||
bool good_;
|
||||
|
||||
@@ -74,6 +80,7 @@ private:
|
||||
public:
|
||||
|
||||
PerformanceReport(Options const &options, std::vector<std::string> const &argument_names, library::OperationKind const &op_kind);
|
||||
~PerformanceReport();
|
||||
|
||||
bool good() const { return good_; }
|
||||
|
||||
@@ -81,8 +88,6 @@ public:
|
||||
void append_result(PerformanceResult result);
|
||||
void append_results(PerformanceResultVector const &results);
|
||||
|
||||
void close();
|
||||
|
||||
public:
|
||||
|
||||
/// Prints the CSV header
|
||||
@@ -91,10 +96,21 @@ public:
|
||||
/// Prints the CSV
|
||||
std::ostream & print_result_csv_(std::ostream &out, PerformanceResult const &result);
|
||||
|
||||
/// @defgroup jUnit Result Generation
|
||||
/// Functions related to generation of the jUnit results
|
||||
/// @{
|
||||
|
||||
std::ostream & print_junit_header_(std::ostream &out);
|
||||
std::ostream & print_junit_result_(std::ostream &out, PerformanceResult const &result);
|
||||
std::ostream & print_junit_footer_(std::ostream &out);
|
||||
|
||||
/// @}
|
||||
|
||||
/// Prints the result in human readable form
|
||||
std::ostream & print_result_pretty_(
|
||||
std::ostream &out,
|
||||
PerformanceResult const &result);
|
||||
PerformanceResult const &result,
|
||||
bool use_shell_coloring = true);
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -961,6 +961,85 @@ bool arg_as_SplitKModeID(
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ConvModeID(
|
||||
library::ConvModeID &conv_mode,
|
||||
KernelArgument::Value const *value_ptr) {
|
||||
|
||||
if (value_ptr->not_null) {
|
||||
if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) {
|
||||
|
||||
conv_mode = library::from_string<library::ConvModeID>(
|
||||
static_cast<EnumeratedTypeArgument::EnumeratedTypeValue const *>(value_ptr)->element);
|
||||
|
||||
if (conv_mode == library::ConvModeID::kInvalid) {
|
||||
throw std::runtime_error(
|
||||
"arg_as_ConvModeID() - illegal cast.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
throw std::runtime_error(
|
||||
"arg_as_ConvModeID() - illegal cast.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ConvModeID(
|
||||
library::ConvModeID &conv_mode,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem) {
|
||||
|
||||
size_t idx = problem_space.argument_index(name);
|
||||
KernelArgument::Value const *value_ptr = problem.at(idx).get();
|
||||
|
||||
return arg_as_ConvModeID(conv_mode, value_ptr);
|
||||
}
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ProviderID(
|
||||
library::Provider &provider,
|
||||
KernelArgument::Value const *value_ptr) {
|
||||
|
||||
if (value_ptr->not_null) {
|
||||
if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) {
|
||||
|
||||
provider = library::from_string<library::Provider>(
|
||||
static_cast<EnumeratedTypeArgument::EnumeratedTypeValue const *>(value_ptr)->element);
|
||||
|
||||
if (provider == library::Provider::kInvalid) {
|
||||
throw std::runtime_error(
|
||||
"arg_as_ProviderID() - illegal cast.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
throw std::runtime_error(
|
||||
"arg_as_ProviderID() - illegal cast.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ProviderID(
|
||||
library::Provider &provider,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem) {
|
||||
|
||||
size_t idx = problem_space.argument_index(name);
|
||||
KernelArgument::Value const *value_ptr = problem.at(idx).get();
|
||||
|
||||
return arg_as_ProviderID(provider, value_ptr);
|
||||
}
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Lexically casts an argument to a given type stored in a byte array. Returns true if not null.
|
||||
bool arg_as_scalar(
|
||||
std::vector<uint8_t> &bytes,
|
||||
@@ -1049,9 +1128,94 @@ bool tensor_description_satisfies(
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns true if conv_kind satisfies the value
|
||||
bool conv_kind_satisfies(
|
||||
library::ConvKind const &conv_kind,
|
||||
EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr) {
|
||||
|
||||
if (value_ptr->not_null) {
|
||||
library::ConvKind conv_kind_cmd_line =
|
||||
library::from_string<library::ConvKind>(value_ptr->element);
|
||||
|
||||
if (conv_kind_cmd_line != library::ConvKind::kUnknown &&
|
||||
conv_kind_cmd_line != conv_kind) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true if conv_kind satisfies the value
|
||||
bool conv_kind_satisfies(
|
||||
library::ConvKind const &conv_kind,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem) {
|
||||
|
||||
size_t idx = problem_space.argument_index(name);
|
||||
KernelArgument::Value const *value_ptr = problem.at(idx).get();
|
||||
|
||||
if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) {
|
||||
return conv_kind_satisfies(
|
||||
conv_kind,
|
||||
static_cast<EnumeratedTypeArgument::EnumeratedTypeValue const *>(value_ptr));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Kernel argument mismatch");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Returns true if a iterator algorithm satisfies the value
|
||||
bool iterator_algorithm_satisfies(
|
||||
library::IteratorAlgorithmID const &iterator_algorithm,
|
||||
EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr) {
|
||||
|
||||
if (value_ptr->not_null) {
|
||||
library::IteratorAlgorithmID iterator_algorithm_cmd_line =
|
||||
library::from_string<library::IteratorAlgorithmID>(value_ptr->element);
|
||||
|
||||
if (iterator_algorithm_cmd_line != library::IteratorAlgorithmID::kNone &&
|
||||
iterator_algorithm_cmd_line != iterator_algorithm) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Returns true if a iterator algorithm satisfies the value
|
||||
bool iterator_algorithm_satisfies(
|
||||
library::IteratorAlgorithmID const &iterator_algorithm,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem) {
|
||||
|
||||
size_t idx = problem_space.argument_index(name);
|
||||
KernelArgument::Value const *value_ptr = problem.at(idx).get();
|
||||
|
||||
if (value_ptr->argument->description->type == ArgumentTypeID::kEnumerated) {
|
||||
return iterator_algorithm_satisfies(
|
||||
iterator_algorithm,
|
||||
static_cast<EnumeratedTypeArgument::EnumeratedTypeValue const *>(value_ptr));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Kernel argument mismatch");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -909,6 +909,37 @@ bool arg_as_SplitKModeID(
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ConvModeID(library::ConvModeID &conv_mode, KernelArgument::Value const *value_ptr);
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ConvModeID(
|
||||
library::ConvModeID &conv_mode,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_IteratorAlgorithmID(library::IteratorAlgorithmID &iterator_algorithm, KernelArgument::Value const *value_ptr);
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_IteratorAlgorithmID(
|
||||
library::IteratorAlgorithmID &iterator_algorithm,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ProviderID(library::Provider &provider, KernelArgument::Value const *value_ptr);
|
||||
|
||||
/// Lexically casts an argument to an int64 if it is defined. Returns true if not null.
|
||||
bool arg_as_ProviderID(
|
||||
library::Provider &provider,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Lexically casts an argument to a given type stored in a byte array. Returns true if not null.
|
||||
bool arg_as_scalar(
|
||||
std::vector<uint8_t> &bytes,
|
||||
@@ -935,10 +966,34 @@ bool tensor_description_satisfies(
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
|
||||
/// Returns true if a conv kind satisfies the value
|
||||
bool conv_kind_satisfies(
|
||||
library::ConvKind const &conv_kind,
|
||||
EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr);
|
||||
|
||||
/// Returns true if a conv kind satisfies the value
|
||||
bool conv_kind_satisfies(
|
||||
library::ConvKind const &conv_kind,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Returns true if a iterator algorithm satisfies the value
|
||||
bool iterator_algorithm_satisfies(
|
||||
library::IteratorAlgorithmID const &iterator_algorithm,
|
||||
EnumeratedTypeArgument::EnumeratedTypeValue const *value_ptr);
|
||||
|
||||
/// Returns true if a iterator algorithm satisfies the value
|
||||
bool iterator_algorithm_satisfies(
|
||||
library::IteratorAlgorithmID const &iterator_algorithm,
|
||||
char const *name,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2019, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
/* \file
|
||||
\brief Defines profiling functionality for reduction operation
|
||||
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
// CUTLASS Library includes
|
||||
#include "cutlass/library/library.h"
|
||||
#include "cutlass/library/util.h"
|
||||
#include "cutlass/library/manifest.h"
|
||||
|
||||
// Profiler includes
|
||||
#include "options.h"
|
||||
#include "device_context.h"
|
||||
#include "operation_profiler.h"
|
||||
#include "performance_result.h"
|
||||
#include "problem_space.h"
|
||||
#if CUTLASS_ENABLE_CUDNN
|
||||
#include "cudnn_helpers.h"
|
||||
#endif //#if CUTLASS_ENABLE_CUDNN
|
||||
#include "debug.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace cutlass {
|
||||
namespace profiler {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Abstract base class for each math function
|
||||
class ReductionOperationProfiler : public OperationProfiler {
|
||||
public:
|
||||
|
||||
|
||||
/// Workspace used
|
||||
struct ReductionWorkspace {
|
||||
|
||||
/// Conv device allocations
|
||||
DeviceAllocation *Workspace;
|
||||
DeviceAllocation *Source;
|
||||
DeviceAllocation *Destination;
|
||||
DeviceAllocation *Reference;
|
||||
|
||||
/// Library configuration and arguments
|
||||
library::ReductionConfiguration configuration;
|
||||
library::ReductionArguments arguments;
|
||||
|
||||
/// Buffer used for the cutlass operations' host workspace
|
||||
std::vector<uint8_t> host_workspace;
|
||||
|
||||
/// Buffer used for the cutlass operations' device workspace
|
||||
DeviceAllocation device_workspace;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
ReductionWorkspace():
|
||||
Workspace(nullptr), Source(nullptr), Destination(nullptr), Reference(nullptr) { }
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Data members
|
||||
//
|
||||
|
||||
/// Reduction problem obtained from problem space
|
||||
MatrixCoord problem_;
|
||||
|
||||
/// Device memory allocations
|
||||
ReductionWorkspace conv_workspace_;
|
||||
|
||||
|
||||
public:
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
/// Ctor
|
||||
ReductionOperationProfiler(Options const &options);
|
||||
|
||||
/// Destructor
|
||||
virtual ~ReductionOperationProfiler();
|
||||
|
||||
/// Prints usage statement for the math function
|
||||
virtual void print_usage(std::ostream &out) const;
|
||||
|
||||
/// Prints examples
|
||||
virtual void print_examples(std::ostream &out) const;
|
||||
|
||||
/// Extracts the problem dimensions
|
||||
virtual Status initialize_configuration(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Initializes workspace
|
||||
virtual Status initialize_workspace(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Verifies CUTLASS against references
|
||||
virtual bool verify_cutlass(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
/// Measures performance results
|
||||
virtual bool profile(
|
||||
Options const &options,
|
||||
PerformanceReport &report,
|
||||
DeviceContext &device_context,
|
||||
library::Operation const *operation,
|
||||
ProblemSpace const &problem_space,
|
||||
ProblemSpace::Problem const &problem);
|
||||
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace profiler
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -227,6 +227,9 @@ void SparseGemmOperationProfiler::SparseGemmProblem::initialize_result(
|
||||
set_argument(result, "C", problem_space,
|
||||
std::string(library::to_string(operation_desc.C.element)) + ":" + library::to_string(operation_desc.C.layout));
|
||||
|
||||
set_argument(result, "E", problem_space,
|
||||
std::string(library::to_string(operation_desc.E.element)) + ":" + library::to_string(operation_desc.E.layout));
|
||||
|
||||
set_argument(result, "m", problem_space, m);
|
||||
set_argument(result, "n", problem_space, n);
|
||||
set_argument(result, "k", problem_space, k);
|
||||
|
||||
@@ -62,6 +62,18 @@ void reorder_column(TensorRef<Element, Layout> dest,
|
||||
}
|
||||
}
|
||||
|
||||
template <int Interleaved, typename Element, typename Layout>
|
||||
void reorder_convK(TensorRef<Element, Layout> dest,
|
||||
TensorRef<Element, Layout> src,
|
||||
cutlass::gemm::GemmCoord problem_size) {
|
||||
|
||||
TensorRef<Element, layout::RowMajorInterleaved<Interleaved>> mappedDest(dest.data(), dest.stride(0));
|
||||
TensorRef<Element, layout::RowMajorInterleaved<Interleaved>> mappedSrc(src.data(), src.stride(0));
|
||||
|
||||
reorder_column<Interleaved>(
|
||||
mappedDest, mappedSrc, problem_size);
|
||||
}
|
||||
|
||||
/// This is needed for the sparse tensor core kernels. The purpose
|
||||
/// is to use ldmatrix to load from shared memory to the register file.
|
||||
template <typename Element, typename LayoutDest, typename LayoutSrc>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,767 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted
|
||||
* provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of
|
||||
* conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of
|
||||
* conditions and the following disclaimer in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
* * Neither the name of the NVIDIA CORPORATION nor the names of its contributors may be used
|
||||
* to endorse or promote products derived from this software without specific prior written
|
||||
* permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TOR (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**************************************************************************************************/
|
||||
|
||||
/*! \file
|
||||
\brief Reference implementation for convolution in host-side code.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cutlass/coord.h"
|
||||
#include "cutlass/functional.h"
|
||||
#include "cutlass/layout/tensor.h"
|
||||
#include "cutlass/numeric_conversion.h"
|
||||
#include "cutlass/numeric_types.h"
|
||||
#include "cutlass/tensor_ref.h"
|
||||
#include "cutlass/tensor_view.h"
|
||||
#include "cutlass/conv/convolution.h"
|
||||
#include "cutlass/conv/conv2d_problem_size.h"
|
||||
#include "cutlass/conv/conv3d_problem_size.h"
|
||||
|
||||
namespace cutlass {
|
||||
namespace reference {
|
||||
namespace host {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Forward propagation
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// y = conv2d(x, w)
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv2dFprop(
|
||||
conv::Conv2dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_x,
|
||||
TensorRef<ElementB, LayoutB> tensor_w,
|
||||
TensorRef<ElementC, LayoutC> tensor_y_in,
|
||||
TensorRef<ElementC, LayoutC> tensor_y_out,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
ConvertOp convert_op;
|
||||
InnerProductOp inner_product_op;
|
||||
|
||||
// Apply MMA and accumulate ElementAccumulator
|
||||
for (int n = 0; n < problem_size.N; ++n) {
|
||||
for (int p = 0; p < problem_size.P; ++p) {
|
||||
for (int q = 0; q < problem_size.Q; ++q) {
|
||||
for (int k = 0; k < problem_size.K; ++k) {
|
||||
|
||||
ElementAccumulator acc = ElementAccumulator();
|
||||
|
||||
for (int r = 0; r < problem_size.R; ++r) {
|
||||
for (int s = 0; s < problem_size.S; ++s) {
|
||||
for (int c = 0; c < problem_size.C; ++c) {
|
||||
|
||||
int filter_r = r;
|
||||
int filter_s = s;
|
||||
|
||||
if (problem_size.mode == cutlass::conv::Mode::kConvolution) {
|
||||
filter_r = problem_size.R - 1 - r;
|
||||
filter_s = problem_size.S - 1 - s;
|
||||
}
|
||||
|
||||
int h = p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h;
|
||||
int w = q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w;
|
||||
|
||||
if (h >= 0 && h < problem_size.H && w >= 0 && w < problem_size.W) {
|
||||
|
||||
ElementA a = tensor_x.at({n, h, w, c});
|
||||
ElementB b = tensor_w.at({k, r, s, c});
|
||||
|
||||
acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Epilogue, compute ElementCompute, convert and store ElementC
|
||||
ElementC c_ref = ElementC();
|
||||
|
||||
if (beta != ElementCompute()) {
|
||||
c_ref = tensor_y_in.at(cutlass::make_Coord(n, p, q, k));
|
||||
}
|
||||
|
||||
tensor_y_out.at(cutlass::make_Coord(n, p, q, k)) =
|
||||
convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Depthwise-separable convolution
|
||||
template <typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementAccumulator,
|
||||
typename ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator> >
|
||||
void Depsep_Fprop(
|
||||
cutlass::TensorView<ElementA, LayoutA> tensor_A,
|
||||
cutlass::TensorView<ElementB, LayoutB> tensor_B,
|
||||
cutlass::TensorView<ElementC, LayoutC> tensor_C,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cutlass::Tensor4DCoord padding,
|
||||
cutlass::Coord<2> conv_stride,
|
||||
cutlass::Coord<2> dilation,
|
||||
cutlass::conv::Mode mode = cutlass::conv::Mode::kCrossCorrelation) {
|
||||
|
||||
ConvertOp convert_op;
|
||||
InnerProductOp inner_product_op;
|
||||
|
||||
// Apply MMA and accumulate ElementAccumulator
|
||||
for (int n = 0; n < tensor_C.extent().n(); ++n) {
|
||||
for (int p = 0; p < tensor_C.extent().h(); ++p) {
|
||||
for (int q = 0; q < tensor_C.extent().w(); ++q) {
|
||||
for (int g = 0; g < tensor_C.extent().c(); ++g) {
|
||||
ElementAccumulator acc = ElementAccumulator();
|
||||
for (int r = 0; r < tensor_B.extent().h(); ++r) {
|
||||
for (int s = 0; s < tensor_B.extent().w(); ++s) {
|
||||
if ((p * conv_stride[0] - padding[0] + r * dilation[0]) < tensor_A.extent().h() &&
|
||||
(p * conv_stride[0] - padding[0] + r * dilation[0]) >= 0 &&
|
||||
(q * conv_stride[1] - padding[2] + s * dilation[1]) < tensor_A.extent().w() &&
|
||||
(q * conv_stride[1] - padding[2] + s * dilation[1]) >= 0) {
|
||||
ElementA a = tensor_A.at(
|
||||
cutlass::make_Coord(n,
|
||||
p * conv_stride[0] - padding[0] + r * dilation[0],
|
||||
q * conv_stride[1] - padding[2] + s * dilation[1],
|
||||
g));
|
||||
|
||||
ElementB b = (mode == cutlass::conv::Mode::kCrossCorrelation)
|
||||
? tensor_B.at(cutlass::make_Coord(g, r, s, 0))
|
||||
: tensor_B.at(cutlass::make_Coord(
|
||||
g, tensor_B.extent().h() - r - 1, tensor_B.extent().w() - s - 1, 0));
|
||||
|
||||
acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Epilogue, compute ElementCompute, convert and store ElementC
|
||||
ElementC c_ref = tensor_C.at(cutlass::make_Coord(n, p, q, g));
|
||||
tensor_C.at(cutlass::make_Coord(n, p, q, g)) =
|
||||
convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Dgrad
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// dx = dgrad(dy, w)
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv2dDgrad(
|
||||
cutlass::conv::Conv2dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_dy,
|
||||
TensorRef<ElementB, LayoutB> tensor_w,
|
||||
TensorRef<ElementC, LayoutC> tensor_dx_in,
|
||||
TensorRef<ElementC, LayoutC> tensor_dx_out,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
ConvertOp convert_op;
|
||||
InnerProductOp inner_product_op;
|
||||
|
||||
// Apply MMA and accumulate ElementAccumulator
|
||||
for (int n = 0; n < problem_size.N; ++n) {
|
||||
for (int h = 0; h < problem_size.H; ++h) {
|
||||
for (int w = 0; w < problem_size.W; ++w) {
|
||||
for (int c = 0; c < problem_size.C; ++c) {
|
||||
|
||||
ElementAccumulator acc = ElementAccumulator();
|
||||
|
||||
for (int r = 0; r < problem_size.R; ++r) {
|
||||
for (int s = 0; s < problem_size.S; ++s) {
|
||||
for (int k = 0; k < problem_size.K; ++k) {
|
||||
|
||||
int filter_r = r;
|
||||
int filter_s = s;
|
||||
|
||||
if (problem_size.mode == cutlass::conv::Mode::kConvolution) {
|
||||
filter_r = problem_size.R - 1 - r;
|
||||
filter_s = problem_size.S - 1 - s;
|
||||
}
|
||||
|
||||
int p = h + problem_size.pad_h - filter_r * problem_size.dilation_h;
|
||||
int q = w + problem_size.pad_w - filter_s * problem_size.dilation_w;
|
||||
|
||||
if (p >= 0 && (p % problem_size.stride_h) == 0 &&
|
||||
q >= 0 && (q % problem_size.stride_w) == 0) {
|
||||
|
||||
p = p / problem_size.stride_h;
|
||||
q = q / problem_size.stride_w;
|
||||
|
||||
if (p < problem_size.P && q < problem_size.Q) {
|
||||
|
||||
ElementA a = tensor_dy.at(cutlass::make_Coord(n, p, q, k));
|
||||
ElementB b = tensor_w.at(cutlass::make_Coord(k, r, s, c));
|
||||
|
||||
acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc);
|
||||
}
|
||||
}
|
||||
|
||||
} // for (K)
|
||||
} // for (S)
|
||||
} // for (R)
|
||||
|
||||
// Apply Epilogue, compute ElementCompute, convert and store ElementC
|
||||
ElementC c_ref = ElementC();
|
||||
|
||||
if (beta != ElementCompute()) {
|
||||
c_ref = tensor_dx_in.at(cutlass::make_Coord(n, h, w, c));
|
||||
}
|
||||
|
||||
tensor_dx_out.at(cutlass::make_Coord(n, h, w, c)) =
|
||||
convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref));
|
||||
|
||||
} // for (C)
|
||||
} // for (W)
|
||||
} // for (H)
|
||||
} // for (N)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Wgrad
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// dw = wgrad(dy, x)
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv2dWgrad(
|
||||
cutlass::conv::Conv2dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_dy,
|
||||
TensorRef<ElementB, LayoutB> tensor_x,
|
||||
TensorRef<ElementC, LayoutC> tensor_dw_in,
|
||||
TensorRef<ElementC, LayoutC> tensor_dw_out,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
InnerProductOp inner_product_op;
|
||||
ConvertOp convert_op;
|
||||
|
||||
// Apply MMA and accumulate ElementAccumulator
|
||||
for (int k = 0; k < problem_size.K; ++k) {
|
||||
for (int r = 0; r < problem_size.R; ++r) {
|
||||
for (int s = 0; s < problem_size.S; ++s) {
|
||||
for (int c = 0; c < problem_size.C; ++c) {
|
||||
|
||||
ElementAccumulator acc = ElementAccumulator();
|
||||
|
||||
for (int n = 0; n < problem_size.N; ++n) {
|
||||
for (int p = 0; p < problem_size.P; ++p) {
|
||||
for (int q = 0; q < problem_size.Q; ++q) {
|
||||
|
||||
cutlass::Tensor4DCoord b_coord;
|
||||
|
||||
int filter_r = r;
|
||||
int filter_s = s;
|
||||
|
||||
if (problem_size.mode == cutlass::conv::Mode::kConvolution) {
|
||||
filter_r = problem_size.R - 1 - r;
|
||||
filter_s = problem_size.S - 1 - s;
|
||||
}
|
||||
|
||||
b_coord = make_Coord(
|
||||
n,
|
||||
p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h,
|
||||
q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w,
|
||||
c);
|
||||
|
||||
if (b_coord.h() < problem_size.H && b_coord.h() >= 0 &&
|
||||
b_coord.w() < problem_size.W && b_coord.w() >= 0) {
|
||||
|
||||
ElementAccumulator a = ElementAccumulator(tensor_dy.at(cutlass::make_Coord(n, p, q, k)));
|
||||
ElementAccumulator b = ElementAccumulator(tensor_x.at(b_coord));
|
||||
acc = inner_product_op(a, b, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Epilogue, compute ElementCompute, convert and store ElementC
|
||||
ElementC c_ref = ElementC();
|
||||
|
||||
if (beta != ElementCompute()) {
|
||||
c_ref = tensor_dw_in.at(cutlass::make_Coord(k, r, s, c));
|
||||
}
|
||||
|
||||
tensor_dw_out.at(cutlass::make_Coord(k, r, s, c)) =
|
||||
convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref));
|
||||
|
||||
} // for (C)
|
||||
} // for (S)
|
||||
} // for (R)
|
||||
} // for (K)
|
||||
}
|
||||
|
||||
/// Generic 2D convolution targeting Conv2dFprop, Conv2dDgrad, and Conv2dWgrad.
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv2d(
|
||||
conv::Operator convolutional_operator,
|
||||
conv::Conv2dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_A,
|
||||
TensorRef<ElementB, LayoutB> tensor_B,
|
||||
TensorRef<ElementC, LayoutC> tensor_C,
|
||||
TensorRef<ElementC, LayoutC> tensor_D,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
switch (convolutional_operator) {
|
||||
case conv::Operator::kFprop:
|
||||
Conv2dFprop<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp, InnerProductOp
|
||||
>(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta);
|
||||
break;
|
||||
|
||||
case conv::Operator::kDgrad:
|
||||
Conv2dDgrad<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp, InnerProductOp
|
||||
>(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta);
|
||||
break;
|
||||
|
||||
case conv::Operator::kWgrad:
|
||||
Conv2dWgrad<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp, InnerProductOp
|
||||
>(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// 3D convolution
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// y = conv3d(x, w)
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv3dFprop(
|
||||
conv::Conv3dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_x,
|
||||
TensorRef<ElementB, LayoutB> tensor_w,
|
||||
TensorRef<ElementC, LayoutC> tensor_y_in,
|
||||
TensorRef<ElementC, LayoutC> tensor_y_out,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
ConvertOp convert_op;
|
||||
InnerProductOp inner_product_op;
|
||||
|
||||
// Apply MMA and accumulate ElementAccumulator
|
||||
for (int n = 0; n < problem_size.N; ++n) {
|
||||
for (int z = 0; z < problem_size.Z; ++z) {
|
||||
for (int p = 0; p < problem_size.P; ++p) {
|
||||
for (int q = 0; q < problem_size.Q; ++q) {
|
||||
for (int k = 0; k < problem_size.K; ++k) {
|
||||
|
||||
ElementAccumulator acc = ElementAccumulator();
|
||||
|
||||
for (int t = 0; t < problem_size.T; ++t) {
|
||||
for (int r = 0; r < problem_size.R; ++r) {
|
||||
for (int s = 0; s < problem_size.S; ++s) {
|
||||
for (int c = 0; c < problem_size.C; ++c) {
|
||||
|
||||
int filter_t = t;
|
||||
int filter_r = r;
|
||||
int filter_s = s;
|
||||
|
||||
if (problem_size.mode == cutlass::conv::Mode::kConvolution) {
|
||||
filter_t = problem_size.T - 1 - t;
|
||||
filter_r = problem_size.R - 1 - r;
|
||||
filter_s = problem_size.S - 1 - s;
|
||||
}
|
||||
|
||||
int d = z * problem_size.stride_d - problem_size.pad_d + filter_t * problem_size.dilation_d;
|
||||
int h = p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h;
|
||||
int w = q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w;
|
||||
|
||||
if (d >= 0 && d < problem_size.D &&
|
||||
h >=0 && h < problem_size.H &&
|
||||
w >= 0 && w < problem_size.W) {
|
||||
|
||||
ElementA a = tensor_x.at({n, d, h, w, c});
|
||||
ElementB b = tensor_w.at({k, t, r, s, c});
|
||||
|
||||
acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Epilogue, compute ElementCompute, convert and store ElementC
|
||||
ElementC c_ref = ElementC();
|
||||
|
||||
if (beta != ElementCompute()) {
|
||||
c_ref = tensor_y_in.at(cutlass::make_Coord(n, z, p, q, k));
|
||||
}
|
||||
|
||||
tensor_y_out.at(cutlass::make_Coord(n, z, p, q, k)) =
|
||||
convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Dgrad
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// dx = dgrad(dy, w)
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv3dDgrad(
|
||||
cutlass::conv::Conv3dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_dy,
|
||||
TensorRef<ElementB, LayoutB> tensor_w,
|
||||
TensorRef<ElementC, LayoutC> tensor_dx_in,
|
||||
TensorRef<ElementC, LayoutC> tensor_dx_out,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
ConvertOp convert_op;
|
||||
InnerProductOp inner_product_op;
|
||||
|
||||
// Apply MMA and accumulate ElementAccumulator
|
||||
for (int n = 0; n < problem_size.N; ++n) {
|
||||
for (int d = 0; d < problem_size.D; ++d) {
|
||||
for (int h = 0; h < problem_size.H; ++h) {
|
||||
for (int w = 0; w < problem_size.W; ++w) {
|
||||
for (int c = 0; c < problem_size.C; ++c) {
|
||||
|
||||
ElementAccumulator acc = ElementAccumulator();
|
||||
|
||||
for (int t = 0; t < problem_size.T; ++t) {
|
||||
for (int r = 0; r < problem_size.R; ++r) {
|
||||
for (int s = 0; s < problem_size.S; ++s) {
|
||||
for (int k = 0; k < problem_size.K; ++k) {
|
||||
|
||||
int filter_t = t;
|
||||
int filter_r = r;
|
||||
int filter_s = s;
|
||||
|
||||
if (problem_size.mode == cutlass::conv::Mode::kConvolution) {
|
||||
filter_t = problem_size.T - 1 - t;
|
||||
filter_r = problem_size.R - 1 - r;
|
||||
filter_s = problem_size.S - 1 - s;
|
||||
}
|
||||
|
||||
int z = d + problem_size.pad_d - filter_t * problem_size.dilation_d;
|
||||
int p = h + problem_size.pad_h - filter_r * problem_size.dilation_h;
|
||||
int q = w + problem_size.pad_w - filter_s * problem_size.dilation_w;
|
||||
|
||||
if (z >= 0 && (z % problem_size.stride_d) == 0 &&
|
||||
p >= 0 && (p % problem_size.stride_h) == 0 &&
|
||||
q >= 0 && (q % problem_size.stride_w) == 0) {
|
||||
|
||||
z = z / problem_size.stride_d;
|
||||
p = p / problem_size.stride_h;
|
||||
q = q / problem_size.stride_w;
|
||||
|
||||
if (z < problem_size.Z && p < problem_size.P && q < problem_size.Q) {
|
||||
|
||||
ElementA a = tensor_dy.at(cutlass::make_Coord(n, z, p, q, k));
|
||||
ElementB b = tensor_w.at(cutlass::make_Coord(k, t, r, s, c));
|
||||
|
||||
acc = inner_product_op(ElementAccumulator(a), ElementAccumulator(b), acc);
|
||||
}
|
||||
}
|
||||
|
||||
} // for (K)
|
||||
} // for (S)
|
||||
} // for (R)
|
||||
} // for (T)
|
||||
|
||||
// Apply Epilogue, compute ElementCompute, convert and store ElementC
|
||||
ElementC c_ref = ElementC();
|
||||
|
||||
if (beta != ElementCompute()) {
|
||||
c_ref = tensor_dx_in.at(cutlass::make_Coord(n, d, h, w, c));
|
||||
}
|
||||
|
||||
tensor_dx_out.at(cutlass::make_Coord(n, d, h, w, c)) =
|
||||
convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref));
|
||||
|
||||
} // for (C)
|
||||
} // for (W)
|
||||
} // for (H)
|
||||
} // for (D)
|
||||
} // for (N)
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Wgrad
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// dw = wgrad(dy, x)
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv3dWgrad(
|
||||
cutlass::conv::Conv3dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_dy,
|
||||
TensorRef<ElementB, LayoutB> tensor_x,
|
||||
TensorRef<ElementC, LayoutC> tensor_dw_in,
|
||||
TensorRef<ElementC, LayoutC> tensor_dw_out,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
InnerProductOp inner_product_op;
|
||||
ConvertOp convert_op;
|
||||
|
||||
// Apply MMA and accumulate ElementAccumulator
|
||||
for (int k = 0; k < problem_size.K; ++k) {
|
||||
for (int t = 0; t < problem_size.T; ++t) {
|
||||
for (int r = 0; r < problem_size.R; ++r) {
|
||||
for (int s = 0; s < problem_size.S; ++s) {
|
||||
for (int c = 0; c < problem_size.C; ++c) {
|
||||
|
||||
ElementAccumulator acc = ElementAccumulator();
|
||||
|
||||
for (int n = 0; n < problem_size.N; ++n) {
|
||||
for (int z = 0; z < problem_size.Z; ++z) {
|
||||
for (int p = 0; p < problem_size.P; ++p) {
|
||||
for (int q = 0; q < problem_size.Q; ++q) {
|
||||
|
||||
int filter_t = t;
|
||||
int filter_r = r;
|
||||
int filter_s = s;
|
||||
|
||||
if (problem_size.mode == cutlass::conv::Mode::kConvolution) {
|
||||
filter_t = problem_size.T - 1 - t;
|
||||
filter_r = problem_size.R - 1 - r;
|
||||
filter_s = problem_size.S - 1 - s;
|
||||
}
|
||||
|
||||
Tensor5DCoord b_coord = make_Coord(
|
||||
n,
|
||||
z * problem_size.stride_d - problem_size.pad_d + filter_t * problem_size.dilation_d,
|
||||
p * problem_size.stride_h - problem_size.pad_h + filter_r * problem_size.dilation_h,
|
||||
q * problem_size.stride_w - problem_size.pad_w + filter_s * problem_size.dilation_w,
|
||||
c);
|
||||
|
||||
if (b_coord.d() < problem_size.D && b_coord.d() >= 0 &&
|
||||
b_coord.h() < problem_size.H && b_coord.h() >= 0 &&
|
||||
b_coord.w() < problem_size.W && b_coord.w() >= 0) {
|
||||
|
||||
ElementAccumulator a = ElementAccumulator(tensor_dy.at(cutlass::make_Coord(n, z, p, q, k)));
|
||||
ElementAccumulator b = ElementAccumulator(tensor_x.at(b_coord));
|
||||
|
||||
acc = inner_product_op(a, b, acc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply Epilogue, compute ElementCompute, convert and store ElementC
|
||||
ElementC c_ref = ElementC();
|
||||
|
||||
if (beta != ElementCompute()) {
|
||||
c_ref = tensor_dw_in.at(cutlass::make_Coord(k, t, r, s, c));
|
||||
}
|
||||
|
||||
tensor_dw_out.at(cutlass::make_Coord(k, t, r, s, c)) =
|
||||
convert_op(alpha * ElementCompute(acc) + beta * ElementCompute(c_ref));
|
||||
|
||||
} // for (C)
|
||||
} // for (S)
|
||||
} // for (R)
|
||||
} // for (T)
|
||||
} // for (K)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Generic 3D convolution targeting Conv2dFprop, Conv2dDgrad, and Conv2dWgrad.
|
||||
template <
|
||||
typename ElementA,
|
||||
typename LayoutA,
|
||||
typename ElementB,
|
||||
typename LayoutB,
|
||||
typename ElementC,
|
||||
typename LayoutC,
|
||||
typename ElementCompute,
|
||||
typename ElementAccumulator = ElementCompute,
|
||||
typename ConvertOp = NumericConverter<ElementC, ElementCompute>,
|
||||
typename InnerProductOp = multiply_add<ElementAccumulator>
|
||||
>
|
||||
void Conv3d(
|
||||
conv::Operator convolutional_operator,
|
||||
conv::Conv3dProblemSize problem_size,
|
||||
TensorRef<ElementA, LayoutA> tensor_A,
|
||||
TensorRef<ElementB, LayoutB> tensor_B,
|
||||
TensorRef<ElementC, LayoutC> tensor_C,
|
||||
TensorRef<ElementC, LayoutC> tensor_D,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta) {
|
||||
|
||||
switch (convolutional_operator) {
|
||||
case conv::Operator::kFprop:
|
||||
Conv3dFprop<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp, InnerProductOp
|
||||
>(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta);
|
||||
break;
|
||||
|
||||
case conv::Operator::kDgrad:
|
||||
Conv3dDgrad<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp, InnerProductOp
|
||||
>(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta);
|
||||
break;
|
||||
|
||||
case conv::Operator::kWgrad:
|
||||
Conv3dWgrad<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementCompute,
|
||||
ElementAccumulator,
|
||||
ConvertOp, InnerProductOp
|
||||
>(problem_size, tensor_A, tensor_B, tensor_C, tensor_D, alpha, beta);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace host
|
||||
} // namespace reference
|
||||
} // namespace cutlass
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -249,6 +249,45 @@ struct Gemm<ElementA, LayoutA, ElementB, LayoutB, ElementC, LayoutC, ScalarType,
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Partial specialization for multiply-add
|
||||
template <typename ElementA, typename LayoutA, typename ElementB,
|
||||
typename LayoutB, typename ElementC, typename LayoutC,
|
||||
typename ScalarType, typename ComputeType>
|
||||
struct Gemm<ElementA, LayoutA, ElementB, LayoutB, ElementC, LayoutC, ScalarType,
|
||||
ComputeType, arch::OpMultiplyAddFastBF16> {
|
||||
|
||||
void operator()(gemm::GemmCoord problem_size, ScalarType alpha,
|
||||
TensorRef<ElementA, LayoutA> tensor_a,
|
||||
TensorRef<ElementB, LayoutB> tensor_b, ScalarType beta,
|
||||
TensorRef<ElementC, LayoutC> tensor_c,
|
||||
ComputeType initial_accum = ComputeType(0)) {
|
||||
static_assert(
|
||||
LayoutA::kRank == 2 && LayoutB::kRank == 2 && LayoutC::kRank == 2,
|
||||
"Tensors must be of rank 2");
|
||||
|
||||
compute_gemm<ElementA, LayoutA, ElementB, LayoutB, ElementC, LayoutC,
|
||||
ScalarType, ComputeType, multiply_add<ComputeType>>(
|
||||
problem_size, alpha, tensor_a, tensor_b, beta, tensor_c, initial_accum);
|
||||
}
|
||||
|
||||
void operator()(gemm::GemmCoord problem_size, ScalarType alpha,
|
||||
TensorRef<ElementA, LayoutA> tensor_a,
|
||||
TensorRef<ElementB, LayoutB> tensor_b, ScalarType beta,
|
||||
TensorRef<ElementC, LayoutC> tensor_c,
|
||||
TensorRef<ElementC, LayoutC> tensor_d,
|
||||
ComputeType initial_accum = ComputeType(0)) {
|
||||
static_assert(
|
||||
LayoutA::kRank == 2 && LayoutB::kRank == 2 && LayoutC::kRank == 2,
|
||||
"Tensors must be of rank 2");
|
||||
|
||||
compute_gemm<ElementA, LayoutA, ElementB, LayoutB, ElementC, LayoutC,
|
||||
ScalarType, ComputeType, multiply_add<ComputeType>>(
|
||||
problem_size, alpha, tensor_a, tensor_b, beta, tensor_c, tensor_d, initial_accum);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Partial specialization for multiply-add-saturate
|
||||
template <typename ElementA, typename LayoutA, typename ElementB,
|
||||
typename LayoutB, typename ElementC, typename LayoutC,
|
||||
|
||||
Reference in New Issue
Block a user