CUTLASS 2.7 (#318)
CUTLASS 2.7 Mainloop fusion for GEMM: summation over A or B Strided DGRAD (optimized iterators) Half-precision GELU_taylor activation functions Use these when accumulation and epilogue compute types are all cutlass::half_t Tuning and bug fixes to fused GEMM + GEMM example Support for smaller than 128b aligned Convolutions: see examples Caching of results to accelerate Convolution unit tests Can be enabled or disabled by running cmake .. -DCUTLASS_TEST_ENABLE_CACHED_RESULTS=OFF Corrections and bug fixes reported by the CUTLASS community Thank you for filing these issues! authored-by: Haicheng Wu haichengw@nvidia.com, Manish Gupta manigupta@nvidia.com, Dustyn Blasig dblasig@nvidia.com, Andrew Kerr akerr@nvidia.com
This commit is contained in:
@@ -134,7 +134,7 @@ cutlass_test_unit_add_executable(
|
||||
conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm70.cu
|
||||
)
|
||||
|
||||
# Conv2d - F16 input, F32 output, F32 accumulation - SM75
|
||||
# Conv - F16 input, F32 output, F32 accumulation - SM75
|
||||
cutlass_test_unit_add_executable(
|
||||
cutlass_test_unit_conv_device_tensorop_f32_sm75
|
||||
|
||||
@@ -144,11 +144,13 @@ cutlass_test_unit_add_executable(
|
||||
|
||||
conv2d_fprop_with_broadcast_sm75.cu
|
||||
conv2d_fprop_with_reduction_sm75.cu
|
||||
|
||||
conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu
|
||||
)
|
||||
|
||||
if (CUTLASS_NVCC_MAX_ARCH GREATER_EQUAL 80)
|
||||
|
||||
# Conv2d - F16 input, F16 output, F16 accumulation
|
||||
# Conv - F16 input, F16 output, F16 accumulation
|
||||
cutlass_test_unit_add_executable(
|
||||
cutlass_test_unit_conv_device_tensorop_f16_sm80
|
||||
|
||||
@@ -157,24 +159,23 @@ if (CUTLASS_NVCC_MAX_ARCH GREATER_EQUAL 80)
|
||||
conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f16nhwc_tensor_op_f16_sm80.cu
|
||||
)
|
||||
|
||||
# Conv2d - F16 input, F32 output, F32 accumulation
|
||||
|
||||
# Conv - F16 input, F32 output, F32 accumulation
|
||||
cutlass_test_unit_add_executable(
|
||||
cutlass_test_unit_conv_device_tensorop_f32_sm80
|
||||
|
||||
# Conv2d
|
||||
conv2d_fprop_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu
|
||||
conv2d_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu
|
||||
conv2d_wgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu
|
||||
|
||||
conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm75.cu
|
||||
conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu
|
||||
|
||||
# Strided Dgrad
|
||||
# Conv2d (Strided Dgrad)
|
||||
conv2d_strided_dgrad_implicit_gemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_sm80.cu
|
||||
|
||||
# Conv3d
|
||||
conv3d_wgrad_implicit_gemm_f16ndhwc_f16ndhwc_f32ndhwc_tensor_op_f32_sm80.cu
|
||||
)
|
||||
|
||||
# Conv2d - TF32 input, F32 output, F32 accumulation
|
||||
|
||||
# Conv - TF32 input, F32 output, F32 accumulation
|
||||
cutlass_test_unit_add_executable(
|
||||
cutlass_test_unit_conv_device_tensorop_f32_tf32_sm80
|
||||
|
||||
@@ -192,7 +193,6 @@ endif()
|
||||
if (CUTLASS_NVCC_MAX_ARCH GREATER_EQUAL 75)
|
||||
|
||||
# Conv2d - S8 input, S32 output, S32 accumulation
|
||||
|
||||
cutlass_test_unit_add_executable(
|
||||
cutlass_test_unit_conv_device_tensorop_s32
|
||||
conv2d_fprop_implicit_gemm_s8nhwc_s8nhwc_s32nhwc_tensor_op_s32_sm75.cu
|
||||
@@ -200,7 +200,6 @@ if (CUTLASS_NVCC_MAX_ARCH GREATER_EQUAL 75)
|
||||
)
|
||||
|
||||
# Conv2d - S8 interleaved input, S8 interleaved output, S32 accumulation
|
||||
|
||||
cutlass_test_unit_add_executable(
|
||||
cutlass_test_unit_conv_device_tensorop_s32_interleaved
|
||||
conv2d_fprop_implicit_gemm_s8ncxhwx_s8cxrskx_s8ncxhwx_tensor_op_s32_sm75.cu
|
||||
|
||||
791
test/unit/conv/device/cache_testbed_output.h
Normal file
791
test/unit/conv/device/cache_testbed_output.h
Normal file
@@ -0,0 +1,791 @@
|
||||
/***************************************************************************************************
|
||||
* Copyright (c) 2017-2021, 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 TORT (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 to construct cached name for
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <typeinfo>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <utility>
|
||||
#include <sstream>
|
||||
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/layout/matrix.h"
|
||||
#include "cutlass/conv/convolution.h"
|
||||
#include "cutlass/conv/conv2d_problem_size.h"
|
||||
|
||||
#include "cutlass/conv/conv3d_problem_size.h"
|
||||
#include "cutlass/core_io.h"
|
||||
#include "cutlass/util/tensor_view_io.h"
|
||||
|
||||
#ifndef CUTLASS_TEST_ENABLE_CACHED_RESULTS
|
||||
#define CUTLASS_TEST_ENABLE_CACHED_RESULTS false
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace test {
|
||||
namespace conv {
|
||||
namespace device {
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Result of a test
|
||||
struct CachedTestKey {
|
||||
|
||||
std::string op; ///< Concatenated string representation of operation performed
|
||||
std::string problem; ///< Concatenated string representation of problem description
|
||||
std::string types; ///< Concatenated string representation of operand types
|
||||
uint32_t A; ///< Hashed result of tensor A
|
||||
uint32_t B; ///< Hashed result of tensor B
|
||||
uint32_t C; ///< Hashed result of tensor C
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
inline CachedTestKey(): A(), B(), C() { }
|
||||
|
||||
inline CachedTestKey(
|
||||
std::string op, ///< Concatenated string representation of operation performed
|
||||
std::string problem, ///< Concatenated string representation of problem description
|
||||
std::string types, ///< Concatenated string representation of operand types
|
||||
uint32_t A, ///< Hashed result of tensor A
|
||||
uint32_t B, ///< Hashed result of tensor B
|
||||
uint32_t C ///< Hashed result of tensor C
|
||||
):
|
||||
op(op), problem(problem), types(types), A(A), B(B), C(C)
|
||||
{ }
|
||||
|
||||
/// Checks for equality of the problem
|
||||
bool operator==(CachedTestKey const &rhs) const {
|
||||
return op == rhs.op && problem == rhs.problem && types == rhs.types && A == rhs.A && B == rhs.B && C == rhs.C;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::istream &operator>>(std::istream &in, CachedTestKey &result) {
|
||||
|
||||
in >> result.op;
|
||||
in >> result.problem;
|
||||
in >> result.types;
|
||||
in >> result.A;
|
||||
in >> result.B;
|
||||
in >> result.C;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, CachedTestKey const &result) {
|
||||
|
||||
out << result.op << " ";
|
||||
out << result.problem << " ";
|
||||
out << result.types << " ";
|
||||
out << result.A << " ";
|
||||
out << result.B << " ";
|
||||
out << result.C << " ";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct CachedTestResult {
|
||||
uint32_t D;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
CachedTestResult(): D() { }
|
||||
|
||||
CachedTestResult(uint32_t D): D(D) { }
|
||||
|
||||
operator bool() const {
|
||||
return bool(D);
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::istream &operator>>(std::istream &in, CachedTestResult &result) {
|
||||
in >> result.D;
|
||||
return in;
|
||||
}
|
||||
|
||||
inline std::ostream &operator<<(std::ostream &out, CachedTestResult const &result) {
|
||||
out << result.D;
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct CachedTestResultListing {
|
||||
|
||||
std::list<std::pair<CachedTestKey, CachedTestResult>> results;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
inline CachedTestResultListing(std::string const &path) {
|
||||
std::ifstream file(path);
|
||||
|
||||
while (file.good()) {
|
||||
CachedTestKey key;
|
||||
file >> key;
|
||||
|
||||
CachedTestResult result;
|
||||
file >> result;
|
||||
|
||||
if (result) {
|
||||
results.push_back(std::make_pair(key, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the cached result
|
||||
std::pair<bool, CachedTestResult> find(CachedTestKey const &rhs) const {
|
||||
for (auto const & result : results) {
|
||||
if (result.first == rhs) {
|
||||
return std::make_pair(true, result.second);
|
||||
}
|
||||
}
|
||||
return std::make_pair(false, CachedTestResult());
|
||||
}
|
||||
|
||||
/// Appends an entry
|
||||
void append(CachedTestKey const &key, CachedTestResult const &result) {
|
||||
if (result) {
|
||||
results.push_back(std::make_pair(key, result));
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the entire listing to a file
|
||||
bool write(std::string const &path) {
|
||||
std::ofstream file(path);
|
||||
if (!file.good()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto const &result : results) {
|
||||
file << result.first << result.second << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Element>
|
||||
struct ScalarEncoder {
|
||||
Element scalar;
|
||||
|
||||
ScalarEncoder(Element s): scalar(s) { }
|
||||
|
||||
std::string str() const {
|
||||
std::stringstream ss;
|
||||
Element s = scalar;
|
||||
if (s < Element()) {
|
||||
s = -s;
|
||||
ss << "n";
|
||||
}
|
||||
ss << s;
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Element>
|
||||
ScalarEncoder<Element> EncodeScalar(Element a) {
|
||||
return ScalarEncoder<Element>(a);
|
||||
}
|
||||
|
||||
template <typename Element>
|
||||
struct ScalarEncoder<cutlass::complex<Element>> {
|
||||
cutlass::complex<Element> scalar;
|
||||
|
||||
ScalarEncoder(cutlass::complex<Element> s): scalar(s) { }
|
||||
|
||||
std::string str() const {
|
||||
std::stringstream ss;
|
||||
ss << EncodeScalar<Element>(scalar.real()) << "_" << EncodeScalar<Element>(scalar.imag()) << "i";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Element>
|
||||
std::ostream &operator<<(std::ostream &out, ScalarEncoder<Element> const &scalar) {
|
||||
out << scalar.str();
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline char const *EncodeOperator(cutlass::conv::Operator conv_op) {
|
||||
switch (conv_op) {
|
||||
case cutlass::conv::Operator::kFprop: return "fprop";
|
||||
case cutlass::conv::Operator::kDgrad: return "dgrad";
|
||||
case cutlass::conv::Operator::kWgrad: return "wgrad";
|
||||
}
|
||||
return "conv_unknown";
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Encode GemmCoord (Gemm problem size)
|
||||
inline std::ostream &EncodeProblemSize(
|
||||
std::ostream &out,
|
||||
cutlass::gemm::GemmCoord const &problem) {
|
||||
|
||||
out << problem.m() << "x" << problem.n() << "x" << problem.k() << "_";
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Encode Conv2dProblemSize
|
||||
inline std::ostream &EncodeProblemSize(
|
||||
std::ostream &out,
|
||||
cutlass::conv::Conv2dProblemSize const &problem) {
|
||||
|
||||
out << problem.N << "x" << problem.H << "x" << problem.W << "x" << problem.C << "_"
|
||||
<< problem.P << "x" << problem.Q << "_" << problem.K << "x" << problem.R << "x" << problem.S << "_";
|
||||
|
||||
out << "pad_h" << problem.pad_h << "w" << problem.pad_w << "_";
|
||||
out << "stride_h" << problem.stride_h << "w" << problem.stride_w << "_";
|
||||
out << "dil_h" << problem.dilation_h << "w" << problem.dilation_w << "_";
|
||||
|
||||
switch (problem.mode) {
|
||||
case cutlass::conv::Mode::kCrossCorrelation:
|
||||
out << "corr";
|
||||
break;
|
||||
case cutlass::conv::Mode::kConvolution:
|
||||
out << "conv";
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Encode Conv3dProblemSize
|
||||
inline std::ostream &EncodeProblemSize(
|
||||
std::ostream &out,
|
||||
cutlass::conv::Conv3dProblemSize const &problem) {
|
||||
|
||||
out << problem.N << "x" << problem.D << "x" << problem.H << "x" << problem.W << "x" << problem.C << "_"
|
||||
<< problem.Z << problem.P << "x" << problem.Q << "_" << problem.K << "x" << problem.R << "x" << problem.S << "_";
|
||||
|
||||
out << "pad_d" << problem.pad_h << "h" << problem.pad_h << "w" << problem.pad_w << "_";
|
||||
out << "stride_d" << problem.stride_d << "h" << problem.stride_h << "w" << problem.stride_w << "_";
|
||||
out << "dil_d" << problem.dilation_d << "h" << problem.dilation_h << "w" << problem.dilation_w << "_";
|
||||
|
||||
switch (problem.mode) {
|
||||
case cutlass::conv::Mode::kCrossCorrelation:
|
||||
out << "corr";
|
||||
break;
|
||||
case cutlass::conv::Mode::kConvolution:
|
||||
out << "conv";
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Element>
|
||||
inline std::string ElementTypeName() {
|
||||
return std::string(typeid(Element).name());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::half_t>() {
|
||||
return "h";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::complex<cutlass::half_t>>() {
|
||||
return "ch";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::bfloat16_t>() {
|
||||
return "bf16";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::complex<cutlass::bfloat16_t>>() {
|
||||
return "cbf16";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::tfloat32_t>() {
|
||||
return "tf32";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::complex<cutlass::tfloat32_t>>() {
|
||||
return "ctf32";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::complex<float>>() {
|
||||
return "c";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::complex<double>>() {
|
||||
return "z";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::Quaternion<float>>() {
|
||||
return "q";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<int8_t>() {
|
||||
return "s8";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<uint8_t>() {
|
||||
return "u8";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::int4b_t>() {
|
||||
return "s4";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string ElementTypeName<cutlass::uint4b_t>() {
|
||||
return "u4";
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Layout>
|
||||
inline std::string LayoutTypeName() {
|
||||
return std::string(typeid(Layout).name());
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::ColumnMajor>() {
|
||||
return "n";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::RowMajor>() {
|
||||
return "t";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::TensorNHWC>() {
|
||||
return "nhwc";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::TensorNCxHWx<32>>() {
|
||||
return "nc32hw32";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::TensorNCxHWx<64>>() {
|
||||
return "nc64hw64";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::TensorCxRSKx<32>>() {
|
||||
return "c32rsk32";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::TensorCxRSKx<64>>() {
|
||||
return "c64rsk64";
|
||||
}
|
||||
|
||||
template <>
|
||||
inline std::string LayoutTypeName<cutlass::layout::TensorNDHWC>() {
|
||||
return "ndhwc";
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <typename Element, typename Layout>
|
||||
inline std::string TensorTypeName() {
|
||||
std::stringstream ss;
|
||||
ss << ElementTypeName<Element>() << LayoutTypeName<Layout>();
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/// Hash function on a byte array
|
||||
struct CRC32 {
|
||||
|
||||
uint32_t table[256];
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
CRC32() {
|
||||
|
||||
uint32_t rem;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
rem = i;
|
||||
for (j = 0; j < 8; j++) {
|
||||
if (rem & 1) {
|
||||
rem >>= 1;
|
||||
rem ^= 0xedb88320;
|
||||
} else
|
||||
rem >>= 1;
|
||||
}
|
||||
table[i] = rem;
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the CRC of an array of bytes
|
||||
uint32_t operator()(void const *start, size_t length, uint32_t crc = uint32_t()) const {
|
||||
uint8_t const *p = static_cast<uint8_t const *>(start);
|
||||
uint8_t const *q = static_cast<uint8_t const *>(start) + length;
|
||||
|
||||
crc = ~crc;
|
||||
|
||||
for (; p != q; ++p) {
|
||||
uint8_t octet = *p;
|
||||
crc = (crc >> 8) ^ table[(crc & 0xff) ^ octet];
|
||||
}
|
||||
|
||||
return ~crc;
|
||||
}
|
||||
};
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <
|
||||
typename Element, typename Layout
|
||||
>
|
||||
uint32_t TensorHash(
|
||||
cutlass::TensorView<Element, Layout> view,
|
||||
CRC32 const &hash = CRC32(),
|
||||
uint32_t crc = uint32_t()
|
||||
) {
|
||||
|
||||
return hash(view.data(), view.capacity() * cutlass::sizeof_bits<Element>::value / 8, crc);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <
|
||||
typename ElementA, typename LayoutA,
|
||||
typename ElementB, typename LayoutB,
|
||||
typename ElementC, typename LayoutC,
|
||||
typename ElementAccumulator,
|
||||
typename ElementCompute
|
||||
>
|
||||
inline std::ostream &EncodeTypes(
|
||||
std::ostream &out
|
||||
) {
|
||||
|
||||
out << TensorTypeName<ElementA, LayoutA>() << "_"
|
||||
<< TensorTypeName<ElementB, LayoutB>() << "_"
|
||||
<< TensorTypeName<ElementC, LayoutC>() << "_"
|
||||
<< ElementTypeName<ElementAccumulator>() << "_"
|
||||
<< ElementTypeName<ElementCompute>();
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <
|
||||
typename ElementA, typename LayoutA,
|
||||
typename ElementB, typename LayoutB,
|
||||
typename ElementC, typename LayoutC,
|
||||
typename ElementAccumulator,
|
||||
typename ElementCompute
|
||||
>
|
||||
inline CachedTestKey CreateCachedGemmTestKey(
|
||||
cutlass::gemm::GemmCoord const &problem,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cutlass::TensorView<ElementA, LayoutA> A,
|
||||
cutlass::TensorView<ElementA, LayoutB> B,
|
||||
cutlass::TensorView<ElementC, LayoutC> C
|
||||
) {
|
||||
|
||||
CachedTestKey key;
|
||||
|
||||
// Encode gemm operator and problem sizes
|
||||
key.op = "gemm";
|
||||
|
||||
std::stringstream ss_problem;
|
||||
EncodeProblemSize(ss_problem, problem);
|
||||
ss_problem << "_alpha" << EncodeScalar(alpha) << "_beta" << EncodeScalar(beta);
|
||||
key.problem = ss_problem.str();
|
||||
|
||||
// Encode problem data types
|
||||
std::stringstream ss_types;
|
||||
EncodeTypes<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute>(ss_types);
|
||||
key.types = ss_types.str();
|
||||
|
||||
// Encode hash for problem data
|
||||
CRC32 crc_hash;
|
||||
key.A = TensorHash(A, crc_hash);
|
||||
key.B = TensorHash(B, crc_hash);
|
||||
key.C = TensorHash(C, crc_hash);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
template <
|
||||
typename ElementA, typename LayoutA,
|
||||
typename ElementB, typename LayoutB,
|
||||
typename ElementC, typename LayoutC,
|
||||
typename ElementAccumulator,
|
||||
typename ElementCompute
|
||||
>
|
||||
inline CachedTestKey CreateCachedConv2dTestKey(
|
||||
|
||||
cutlass::conv::Operator conv_operator,
|
||||
cutlass::conv::Conv2dProblemSize const &problem,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cutlass::TensorView<ElementA, LayoutA> A,
|
||||
cutlass::TensorView<ElementA, LayoutB> B,
|
||||
cutlass::TensorView<ElementC, LayoutC> C
|
||||
) {
|
||||
|
||||
CachedTestKey key;
|
||||
|
||||
// Encode conv2d operator and problem sizes
|
||||
key.op = "conv2d";
|
||||
|
||||
std::stringstream ss_problem;
|
||||
ss_problem << EncodeOperator(conv_operator) << "_";
|
||||
EncodeProblemSize(ss_problem, problem);
|
||||
ss_problem << "_alpha" << EncodeScalar(alpha) << "_beta" << EncodeScalar(beta);
|
||||
|
||||
key.problem = ss_problem.str();
|
||||
|
||||
// Encode problem data types
|
||||
std::stringstream ss_types;
|
||||
EncodeTypes<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute>(ss_types);
|
||||
key.types = ss_types.str();
|
||||
|
||||
// Encode hash for problem data
|
||||
CRC32 crc_hash;
|
||||
|
||||
key.A = TensorHash(A, crc_hash);
|
||||
key.B = TensorHash(B, crc_hash);
|
||||
key.C = TensorHash(C, crc_hash);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <
|
||||
typename ElementA, typename LayoutA,
|
||||
typename ElementB, typename LayoutB,
|
||||
typename ElementC, typename LayoutC,
|
||||
typename ElementAccumulator,
|
||||
typename ElementCompute
|
||||
>
|
||||
inline CachedTestKey CreateCachedConv2dWithBroadcastTestKey(
|
||||
|
||||
cutlass::conv::Operator conv_operator,
|
||||
cutlass::conv::Conv2dProblemSize const &problem,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cutlass::TensorView<ElementA, LayoutA> A,
|
||||
cutlass::TensorView<ElementA, LayoutB> B,
|
||||
cutlass::TensorView<ElementC, LayoutC> C
|
||||
) {
|
||||
|
||||
CachedTestKey key;
|
||||
|
||||
// Encode conv2d operator and problem sizes
|
||||
key.op = "conv2d_with_broadcast";
|
||||
|
||||
std::stringstream ss_problem;
|
||||
ss_problem << EncodeOperator(conv_operator) << "_";
|
||||
EncodeProblemSize(ss_problem, problem);
|
||||
ss_problem << "_alpha" << EncodeScalar(alpha) << "_beta" << EncodeScalar(beta);
|
||||
|
||||
key.problem = ss_problem.str();
|
||||
|
||||
// Encode problem data types
|
||||
std::stringstream ss_types;
|
||||
EncodeTypes<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute>(ss_types);
|
||||
key.types = ss_types.str();
|
||||
|
||||
// Encode hash for problem data
|
||||
CRC32 crc_hash;
|
||||
|
||||
key.A = TensorHash(A, crc_hash);
|
||||
key.B = TensorHash(B, crc_hash);
|
||||
key.C = TensorHash(C, crc_hash);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <
|
||||
typename ElementA, typename LayoutA,
|
||||
typename ElementB, typename LayoutB,
|
||||
typename ElementC, typename LayoutC,
|
||||
typename ElementAccumulator,
|
||||
typename ElementCompute
|
||||
>
|
||||
inline CachedTestKey CreateCachedConv2dWithReductionTestKey(
|
||||
|
||||
cutlass::conv::Operator conv_operator,
|
||||
cutlass::conv::Conv2dProblemSize const &problem,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cutlass::TensorView<ElementA, LayoutA> A,
|
||||
cutlass::TensorView<ElementA, LayoutB> B,
|
||||
cutlass::TensorView<ElementC, LayoutC> C
|
||||
) {
|
||||
|
||||
CachedTestKey key;
|
||||
|
||||
// Encode conv2d operator and problem sizes
|
||||
key.op = "conv2d_with_reduction";
|
||||
|
||||
std::stringstream ss_problem;
|
||||
ss_problem << EncodeOperator(conv_operator) << "_";
|
||||
EncodeProblemSize(ss_problem, problem);
|
||||
ss_problem << "_alpha" << EncodeScalar(alpha) << "_beta" << EncodeScalar(beta);
|
||||
|
||||
key.problem = ss_problem.str();
|
||||
|
||||
// Encode problem data types
|
||||
std::stringstream ss_types;
|
||||
EncodeTypes<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute>(ss_types);
|
||||
key.types = ss_types.str();
|
||||
|
||||
// Encode hash for problem data
|
||||
CRC32 crc_hash;
|
||||
|
||||
key.A = TensorHash(A, crc_hash);
|
||||
key.B = TensorHash(B, crc_hash);
|
||||
key.C = TensorHash(C, crc_hash);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <
|
||||
typename ElementA, typename LayoutA,
|
||||
typename ElementB, typename LayoutB,
|
||||
typename ElementC, typename LayoutC,
|
||||
typename ElementAccumulator,
|
||||
typename ElementCompute
|
||||
>
|
||||
inline CachedTestKey CreateCachedConv3dTestKey(
|
||||
cutlass::conv::Operator conv_operator,
|
||||
cutlass::conv::Conv3dProblemSize const &problem,
|
||||
ElementCompute alpha,
|
||||
ElementCompute beta,
|
||||
cutlass::TensorView<ElementA, LayoutA> A,
|
||||
cutlass::TensorView<ElementA, LayoutB> B,
|
||||
cutlass::TensorView<ElementC, LayoutC> C
|
||||
) {
|
||||
|
||||
CachedTestKey key;
|
||||
|
||||
// Encode conv3d operator and problem sizes
|
||||
key.op = "conv3d";
|
||||
|
||||
std::stringstream ss_problem;
|
||||
|
||||
ss_problem << EncodeOperator(conv_operator) << "_";
|
||||
EncodeProblemSize(ss_problem, problem);
|
||||
ss_problem << "_alpha" << EncodeScalar(alpha) << "_beta" << EncodeScalar(beta);
|
||||
|
||||
key.problem = ss_problem.str();
|
||||
|
||||
// Encode problem data types
|
||||
std::stringstream ss_types;
|
||||
EncodeTypes<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute>(ss_types);
|
||||
key.types = ss_types.str();
|
||||
|
||||
// Encode problem data
|
||||
CRC32 crc_hash;
|
||||
key.A = TensorHash(A, crc_hash);
|
||||
key.B = TensorHash(B, crc_hash);
|
||||
key.C = TensorHash(C, crc_hash);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
} // namespace device
|
||||
} // nammespace conv
|
||||
} // namespace test
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -170,6 +170,25 @@ TEST(SM80_Device_Conv2d_Fprop_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_tens
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
// run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 4, 4, 14}, // input size (NHWC)
|
||||
{8, 3, 3, 14}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
// run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 23, 56, 98}, // input size (NHWC)
|
||||
{128, 3, 3, 98}, // filter size (KRSC)
|
||||
{4, 0, 5, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
|
||||
/// Run all unit test sizes with device-level Conv2d instance
|
||||
EXPECT_TRUE(test::conv::device::TestAllConv2d<Conv2dFprop>(problem_size_list));
|
||||
}
|
||||
@@ -225,6 +244,25 @@ TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_ten
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
// run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 4, 4, 14}, // input size (NHWC)
|
||||
{8, 3, 3, 14}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
// run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 23, 56, 98}, // input size (NHWC)
|
||||
{128, 3, 3, 98}, // filter size (KRSC)
|
||||
{4, 0, 5, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
|
||||
/// Run all unit test sizes with device-level Conv2d instance
|
||||
EXPECT_TRUE(test::conv::device::TestAllConv2d<Conv2dFprop>(problem_size_list));
|
||||
}
|
||||
@@ -280,6 +318,24 @@ TEST(SM80_Device_Conv2d_Fprop_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f16nhwc_ten
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
// run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 4, 4, 28}, // input size (NHWC)
|
||||
{8, 3, 3, 28}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
// run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 23, 56, 100}, // input size (NHWC)
|
||||
{128, 3, 3, 100}, // filter size (KRSC)
|
||||
{4, 0, 5, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
/// Run all unit test sizes with device-level Conv2d instance
|
||||
EXPECT_TRUE(test::conv::device::TestAllConv2d<Conv2dFprop>(problem_size_list));
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{1, 7, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 3, 3, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
@@ -190,7 +190,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{1, 7, 9, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 4, 4, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
@@ -198,7 +198,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{2, 7, 9, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 5, 5, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
@@ -206,7 +206,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{3, 7, 9, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 6, 5, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
@@ -214,7 +214,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{3, 7, 9, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 6, 6, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
@@ -222,7 +222,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{3, 7, 9, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 7, 7, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
@@ -234,7 +234,7 @@ struct TestbedConv2dProblemSizes {
|
||||
// C < CTA::K and non-multiples of CTA::K. Typical CTA::K = {32, 64}
|
||||
////////////////////////////////////////////////////////////////////////////////////////////
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 11, 11, minimum_channel_size}, // input size (NHWC)
|
||||
{1, 11, 7, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 1, 1, minimum_channel_size}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
@@ -242,7 +242,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 11, 11, minimum_channel_size}, // input size (NHWC)
|
||||
{1, 11, 7, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 3, 3, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
@@ -250,7 +250,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 13, 13, minimum_channel_size}, // input size (NHWC)
|
||||
{1, 13, 11, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 1, 1, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
@@ -258,40 +258,40 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 2, 2, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 17, 19, minimum_channel_size}, // input size (NHWC)
|
||||
{16, 2, 2, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 5, 5, minimum_channel_size}, // input size (NHWC)
|
||||
{8, 3, 3, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 23, 5, minimum_channel_size}, // input size (NHWC)
|
||||
{16, 3, 3, minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, 8}, // input size (NHWC)
|
||||
{8, 3, 3, 8}, // filter size (KRSC)
|
||||
{1, 13, 17, 8}, // input size (NHWC)
|
||||
{24, 3, 3, 8}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 8, 8, 8}, // input size (NHWC)
|
||||
{8, 3, 3, 8}, // filter size (KRSC)
|
||||
{1, 23, 21, 8}, // input size (NHWC)
|
||||
{24, 3, 3, 8}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 16, 16, 8}, // input size (NHWC)
|
||||
{8, 3, 3, 8}, // filter size (KRSC)
|
||||
{1, 20, 24, 8}, // input size (NHWC)
|
||||
{40, 3, 3, 8}, // filter size (KRSC)
|
||||
{3, 3, 3, 3}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
@@ -352,7 +352,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 16, 16, 64 + minimum_channel_size}, // input size (NHWC)
|
||||
{1, 16, 24, 64 + minimum_channel_size}, // input size (NHWC)
|
||||
{96, 3, 3, 64 + minimum_channel_size}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
@@ -363,7 +363,7 @@ struct TestbedConv2dProblemSizes {
|
||||
// Medium input size, filter size (1x1, 3,x3, 5x5, 7x7), stride (2, 2)
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 16, 16, 288}, // input size (NHWC)
|
||||
{1, 13, 16, 288}, // input size (NHWC)
|
||||
{160, 5, 5, 288}, // filter size (KRSC)
|
||||
{2, 2, 2, 2}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
@@ -371,7 +371,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 55, 55, 256}, // input size (NHWC)
|
||||
{1, 55, 51, 256}, // input size (NHWC)
|
||||
{512, 1, 1, 256}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
@@ -379,7 +379,7 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 80, 80, 32}, // input size (NHWC)
|
||||
{1, 71, 80, 32}, // input size (NHWC)
|
||||
{64, 5, 5, 32}, // filter size (KRSC)
|
||||
{2, 2, 2, 2}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
@@ -398,7 +398,7 @@ struct TestbedConv2dProblemSizes {
|
||||
// Medium input size stride (3, 3), filter (3, 3), non-default padding
|
||||
////////////////////////////////////////////////////////////////////////////////////
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 27, 27, 256}, // input size (NHWC)
|
||||
{1, 27, 23, 256}, // input size (NHWC)
|
||||
{512, 3, 3, 256}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{3, 3}, // stride (stride_h, stride_w)
|
||||
@@ -464,16 +464,16 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{32, 32, 32, 32}, // input size (NHWC)
|
||||
{32, 1, 1, 32}, // filter size (KRSC)
|
||||
{32, 24, 32, 32}, // input size (NHWC)
|
||||
{32, 1, 2, 32}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{4, 3, 3, 128}, // input size (NHWC)
|
||||
{256, 3, 3, 128}, // filter size (KRSC)
|
||||
{4, 4, 5, 128}, // input size (NHWC)
|
||||
{256, 3, 6, 128}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
{1, 1}, // dilation (dilation_h, dilation_w)
|
||||
@@ -481,8 +481,8 @@ struct TestbedConv2dProblemSizes {
|
||||
));
|
||||
|
||||
conv2d_default_sizes.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{4, 1, 1, 256}, // input size (NHWC)
|
||||
{328, 3, 3, 256}, // filter size (KRSC)
|
||||
{4, 2, 3, 256}, // input size (NHWC)
|
||||
{328, 3, 5, 256}, // filter size (KRSC)
|
||||
{1, 1, 1, 1}, // padding (pad_h, _, pad_w, _)
|
||||
{1, 1}, // stride (stride_h, stride_w)
|
||||
{1, 1}, // dilation (dilation_h, dilation_w)
|
||||
|
||||
@@ -231,4 +231,137 @@ TEST(SM80_Device_Conv2d_Strided_Dgrad_Analytic_ImplicitGemm_f16nhwc_f16nhwc_f32n
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Strided Dgrad (Optimized)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(SM80_Device_Conv2d_Strided_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32,
|
||||
128x128_32x3_64x64x32) {
|
||||
|
||||
/// Conv operation element types for the Gemm equivalent (ImplicitGemm)
|
||||
using ElementA = cutlass::half_t;
|
||||
using ElementB = cutlass::half_t;
|
||||
using ElementC = float;
|
||||
using ElementAccumulator = float;
|
||||
using ElementCompute = float;
|
||||
|
||||
/// Device-level Conv2d instance
|
||||
using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad<
|
||||
ElementA, cutlass::layout::TensorNHWC,
|
||||
ElementB, cutlass::layout::TensorNHWC,
|
||||
ElementC, cutlass::layout::TensorNHWC,
|
||||
ElementAccumulator,
|
||||
cutlass::arch::OpClassTensorOp,
|
||||
cutlass::arch::Sm80,
|
||||
cutlass::gemm::GemmShape<128, 128, 32>,
|
||||
cutlass::gemm::GemmShape<64, 64, 32>,
|
||||
cutlass::gemm::GemmShape<16, 8, 16>,
|
||||
cutlass::epilogue::thread::LinearCombination<
|
||||
ElementC,
|
||||
128 / cutlass::sizeof_bits<ElementC>::value,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>,
|
||||
cutlass::conv::threadblock::StridedDgradIdentityThreadblockSwizzle<>,
|
||||
3,
|
||||
cutlass::arch::OpMultiplyAdd,
|
||||
cutlass::conv::IteratorAlgorithm::kOptimized,
|
||||
cutlass::conv::StrideSupport::kStrided
|
||||
>::Kernel;
|
||||
|
||||
using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution<Conv2dDgradKernel>;
|
||||
|
||||
|
||||
test::conv::device::Conv2dProblemVector problem_size_list;
|
||||
|
||||
#if 0 // run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 56, 56, 8}, // input size (NHWC)
|
||||
{8, 1, 1, 8}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 55, 55, 8}, // input size (NHWC)
|
||||
{8, 1, 1, 8}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
#endif
|
||||
|
||||
/// Run all unit test sizes with device-level Conv2d instance
|
||||
EXPECT_TRUE(test::conv::device::TestAllConv2d<Conv2dDgrad>(problem_size_list));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TEST(SM80_Device_Conv2d_Strided_Dgrad_Optimized_ImplicitGemm_f16nhwc_f16nhwc_f32nhwc_tensor_op_f32_align4,
|
||||
128x128_32x3_64x64x32) {
|
||||
|
||||
/// Conv operation element types for the Gemm equivalent (ImplicitGemm)
|
||||
using ElementA = cutlass::half_t;
|
||||
using ElementB = cutlass::half_t;
|
||||
using ElementC = float;
|
||||
using ElementAccumulator = float;
|
||||
using ElementCompute = float;
|
||||
|
||||
/// Device-level Conv2d instance
|
||||
using Conv2dDgradKernel = typename cutlass::conv::kernel::DefaultConv2dDgrad<
|
||||
ElementA, cutlass::layout::TensorNHWC,
|
||||
ElementB, cutlass::layout::TensorNHWC,
|
||||
ElementC, cutlass::layout::TensorNHWC,
|
||||
ElementAccumulator,
|
||||
cutlass::arch::OpClassTensorOp,
|
||||
cutlass::arch::Sm80,
|
||||
cutlass::gemm::GemmShape<128, 128, 32>,
|
||||
cutlass::gemm::GemmShape<64, 64, 32>,
|
||||
cutlass::gemm::GemmShape<16, 8, 16>,
|
||||
cutlass::epilogue::thread::LinearCombination<
|
||||
ElementC,
|
||||
4,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>,
|
||||
cutlass::conv::threadblock::StridedDgradIdentityThreadblockSwizzle<>,
|
||||
3,
|
||||
cutlass::arch::OpMultiplyAdd,
|
||||
cutlass::conv::IteratorAlgorithm::kOptimized,
|
||||
cutlass::conv::StrideSupport::kStrided,
|
||||
4,
|
||||
4
|
||||
>::Kernel;
|
||||
|
||||
using Conv2dDgrad = cutlass::conv::device::ImplicitGemmConvolution<Conv2dDgradKernel>;
|
||||
|
||||
|
||||
test::conv::device::Conv2dProblemVector problem_size_list;
|
||||
|
||||
// run specific problem size in the unit test first
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 56, 56, 12}, // input size (NHWC)
|
||||
{8, 1, 1, 12}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
problem_size_list.push_back(cutlass::conv::Conv2dProblemSize(
|
||||
{1, 55, 55, 12}, // input size (NHWC)
|
||||
{8, 1, 1, 12}, // filter size (KRSC)
|
||||
{0, 0, 0, 0}, // padding (pad_h, _, pad_w, _)
|
||||
{2, 2}, // stride (stride_h, stride_w)
|
||||
{1, 1} // dilation (dilation_h, dilation_w)
|
||||
));
|
||||
|
||||
/// Run all unit test sizes with device-level Conv2d instance
|
||||
EXPECT_TRUE(test::conv::device::TestAllConv2d<Conv2dDgrad>(problem_size_list));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#endif // CUTLASS_ARCH_MMA_SM80_SUPPORTED
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "cutlass/core_io.h"
|
||||
#include "cutlass/util/tensor_view_io.h"
|
||||
|
||||
#include "cache_testbed_output.h"
|
||||
|
||||
namespace test {
|
||||
namespace conv {
|
||||
namespace device {
|
||||
@@ -116,7 +118,6 @@ public:
|
||||
cutlass::Distribution::Kind dist_kind,
|
||||
uint64_t seed) {
|
||||
|
||||
//cutlass::reference::host::TensorFill(view, Element(1.0f));
|
||||
if (dist_kind == cutlass::Distribution::Uniform) {
|
||||
|
||||
int scope;
|
||||
@@ -126,7 +127,12 @@ public:
|
||||
scope = 2;
|
||||
}
|
||||
else if (bits == 16) {
|
||||
scope = 3;
|
||||
if (cutlass::sizeof_bits<ElementAccumulator>::value <= 16) {
|
||||
scope = 3;
|
||||
}
|
||||
else {
|
||||
scope = 5;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope = 8;
|
||||
@@ -137,6 +143,7 @@ public:
|
||||
else if (dist_kind == cutlass::Distribution::Identity) {
|
||||
|
||||
cutlass::reference::host::TensorFillIdentity(view);
|
||||
|
||||
}
|
||||
else if (dist_kind == cutlass::Distribution::Gaussian) {
|
||||
|
||||
@@ -321,6 +328,50 @@ public:
|
||||
|
||||
tensor_D_computed.sync_host();
|
||||
|
||||
//
|
||||
// Reference check - support caching results
|
||||
//
|
||||
|
||||
CachedTestKey cached_test_key = CreateCachedConv2dTestKey<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
problem_size,
|
||||
alpha,
|
||||
beta,
|
||||
tensor_A.host_view(),
|
||||
tensor_B.host_view(),
|
||||
tensor_C.host_view()
|
||||
);
|
||||
|
||||
//
|
||||
// Look for the cached key
|
||||
//
|
||||
|
||||
bool cached_result_loaded = false;
|
||||
CachedTestResult cached_test_result;
|
||||
|
||||
std::string conv2d_result_cache_name =
|
||||
std::string("cached_results_") + CUTLASS_TARGET_NAME + ".txt";
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
auto cached = cached_results.find(cached_test_key);
|
||||
|
||||
cached_result_loaded = cached.first;
|
||||
if (cached_result_loaded) {
|
||||
cached_test_result = cached.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
|
||||
#if CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED
|
||||
|
||||
cutlass::reference::device::Conv2d<
|
||||
@@ -367,9 +418,32 @@ public:
|
||||
beta);
|
||||
|
||||
#endif
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
cached_test_result.D = TensorHash(tensor_D_reference.host_view());
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
cached_results.append(cached_test_key, cached_test_result);
|
||||
cached_results.write(conv2d_result_cache_name);
|
||||
}
|
||||
} // if (!cached_result_loaded)
|
||||
|
||||
uint32_t tensor_D_hash = TensorHash(tensor_D_computed.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
passed = (tensor_D_hash == cached_test_result.D);
|
||||
|
||||
EXPECT_EQ(tensor_D_hash, cached_test_result.D)
|
||||
<< "Hash-based comparison failed for key:" << "\n" << cached_test_key << "\n";
|
||||
}
|
||||
else {
|
||||
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(passed);
|
||||
|
||||
@@ -416,9 +490,18 @@ public:
|
||||
results
|
||||
<< "\nA:\n" << tensor_A.host_view() << "\n"
|
||||
<< "\nB:\n" << tensor_B.host_view() << "\n"
|
||||
<< "\nC:\n" << tensor_C.host_view() << "\n"
|
||||
<< "\nD reference:\n" << tensor_D_reference.host_view() << "\n"
|
||||
<< "\nD computed:\n" << tensor_D_computed.host_view() << "\n";
|
||||
<< "\nC:\n" << tensor_C.host_view() << "\n";
|
||||
|
||||
results << "\nD reference (hash: " << cached_test_result.D << ")\n";
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
results
|
||||
<< tensor_D_reference.host_view() << "\n";
|
||||
}
|
||||
|
||||
results
|
||||
<< "\nD computed (hash: " << tensor_D_hash << ")\n"
|
||||
<< tensor_D_computed.host_view() << "\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
#include "cutlass/core_io.h"
|
||||
#include "cutlass/util/tensor_view_io.h"
|
||||
|
||||
#include "cache_testbed_output.h"
|
||||
|
||||
namespace test {
|
||||
namespace conv {
|
||||
namespace device {
|
||||
@@ -280,6 +282,50 @@ public:
|
||||
|
||||
tensor_D_computed.sync_host();
|
||||
|
||||
//
|
||||
// Reference check - support caching results
|
||||
//
|
||||
|
||||
CachedTestKey cached_test_key = CreateCachedConv2dTestKey<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
problem_size,
|
||||
alpha,
|
||||
beta,
|
||||
tensor_A.host_view(),
|
||||
tensor_B.host_view(),
|
||||
tensor_C.host_view()
|
||||
);
|
||||
|
||||
//
|
||||
// Look for the cached key
|
||||
//
|
||||
|
||||
bool cached_result_loaded = false;
|
||||
CachedTestResult cached_test_result;
|
||||
|
||||
std::string conv2d_result_cache_name =
|
||||
std::string("cached_results_") + CUTLASS_TARGET_NAME + ".txt";
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
auto cached = cached_results.find(cached_test_key);
|
||||
|
||||
cached_result_loaded = cached.first;
|
||||
if (cached_result_loaded) {
|
||||
cached_test_result = cached.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
|
||||
#if CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED
|
||||
|
||||
cutlass::reference::device::Conv2d<
|
||||
@@ -332,9 +378,32 @@ public:
|
||||
beta);
|
||||
|
||||
#endif
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
cached_test_result.D = TensorHash(tensor_D_reference.host_view());
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
cached_results.append(cached_test_key, cached_test_result);
|
||||
cached_results.write(conv2d_result_cache_name);
|
||||
}
|
||||
} // if (!cached_result_loaded)
|
||||
|
||||
uint32_t tensor_D_hash = TensorHash(tensor_D_computed.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
passed = (tensor_D_hash == cached_test_result.D);
|
||||
|
||||
EXPECT_EQ(tensor_D_hash, cached_test_result.D)
|
||||
<< "Hash-based comparison failed for key:" << "\n" << cached_test_key << "\n";
|
||||
}
|
||||
else {
|
||||
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(passed);
|
||||
|
||||
@@ -345,12 +414,12 @@ public:
|
||||
<< (split_k_mode == cutlass::conv::SplitKMode::kSerial ? "serial_reduction_" : "parallel_reduction_")
|
||||
<< (Conv2d::kConvolutionalOperator == cutlass::conv::Operator::kFprop ? "fprop_" :
|
||||
(Conv2d::kConvolutionalOperator == cutlass::conv::Operator::kDgrad ? "dgrad_" : "wgrad_"))
|
||||
<< "nhwc_"
|
||||
<< "ncxhwx_"
|
||||
<< problem_size.N << "x"
|
||||
<< problem_size.H << "x"
|
||||
<< problem_size.W << "x"
|
||||
<< problem_size.C
|
||||
<< "_krsc_"
|
||||
<< "_cxrskx_"
|
||||
<< problem_size.K << "x"
|
||||
<< problem_size.R << "x"
|
||||
<< problem_size.S << "x"
|
||||
@@ -381,10 +450,18 @@ public:
|
||||
results
|
||||
<< "\nA:\n" << tensor_A.host_view() << "\n"
|
||||
<< "\nB:\n" << tensor_B.host_view() << "\n"
|
||||
<< "\nB_reordered =\n" << tensor_B_reordered.host_view() << "\n"
|
||||
<< "\nC:\n" << tensor_C.host_view() << "\n"
|
||||
<< "\nD reference:\n" << tensor_D_reference.host_view() << "\n"
|
||||
<< "\nD computed:\n" << tensor_D_computed.host_view() << "\n";
|
||||
<< "\nC:\n" << tensor_C.host_view() << "\n";
|
||||
|
||||
results << "\nD reference (hash: " << cached_test_result.D << ")\n";
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
results
|
||||
<< tensor_D_reference.host_view() << "\n";
|
||||
}
|
||||
|
||||
results
|
||||
<< "\nD computed (hash: " << tensor_D_hash << ")\n"
|
||||
<< tensor_D_computed.host_view() << "\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "cutlass/core_io.h"
|
||||
#include "cutlass/util/tensor_view_io.h"
|
||||
|
||||
#include "cache_testbed_output.h"
|
||||
|
||||
namespace test {
|
||||
namespace conv {
|
||||
namespace device {
|
||||
@@ -109,11 +111,17 @@ public:
|
||||
scope = 2;
|
||||
}
|
||||
else if (bits == 16) {
|
||||
scope = 3;
|
||||
if (cutlass::sizeof_bits<ElementAccumulator>::value <= 16) {
|
||||
scope = 3;
|
||||
}
|
||||
else {
|
||||
scope = 5;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope = 8;
|
||||
}
|
||||
|
||||
cutlass::reference::host::TensorFillRandomUniform(
|
||||
view, seed, scope, -scope, 0);
|
||||
}
|
||||
@@ -263,6 +271,50 @@ public:
|
||||
|
||||
tensor_D_computed.sync_host();
|
||||
|
||||
//
|
||||
// Reference check - support caching results
|
||||
//
|
||||
|
||||
CachedTestKey cached_test_key = CreateCachedConv2dWithBroadcastTestKey<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
problem_size,
|
||||
alpha,
|
||||
beta,
|
||||
tensor_A.host_view(),
|
||||
tensor_B.host_view(),
|
||||
tensor_C.host_view()
|
||||
);
|
||||
|
||||
//
|
||||
// Look for the cached key
|
||||
//
|
||||
|
||||
bool cached_result_loaded = false;
|
||||
CachedTestResult cached_test_result;
|
||||
|
||||
std::string conv2d_result_cache_name =
|
||||
std::string("cached_results_") + CUTLASS_TARGET_NAME + ".txt";
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
auto cached = cached_results.find(cached_test_key);
|
||||
|
||||
cached_result_loaded = cached.first;
|
||||
if (cached_result_loaded) {
|
||||
cached_test_result = cached.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
|
||||
#if CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED
|
||||
|
||||
cutlass::reference::device::Conv2d<
|
||||
@@ -309,9 +361,33 @@ public:
|
||||
beta);
|
||||
|
||||
#endif
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
cached_test_result.D = TensorHash(tensor_D_reference.host_view());
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
cached_results.append(cached_test_key, cached_test_result);
|
||||
cached_results.write(conv2d_result_cache_name);
|
||||
}
|
||||
} // if (!cached_result_loaded)
|
||||
|
||||
|
||||
uint32_t tensor_D_hash = TensorHash(tensor_D_computed.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
passed = (tensor_D_hash == cached_test_result.D);
|
||||
|
||||
EXPECT_EQ(tensor_D_hash, cached_test_result.D)
|
||||
<< "Hash-based comparison failed for key:" << "\n" << cached_test_key << "\n";
|
||||
}
|
||||
else {
|
||||
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(passed);
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "cutlass/core_io.h"
|
||||
#include "cutlass/util/tensor_view_io.h"
|
||||
|
||||
#include "cache_testbed_output.h"
|
||||
|
||||
namespace test {
|
||||
namespace conv {
|
||||
namespace device {
|
||||
@@ -114,7 +116,12 @@ public:
|
||||
scope = 2;
|
||||
}
|
||||
else if (bits == 16) {
|
||||
scope = 3;
|
||||
if (cutlass::sizeof_bits<ElementAccumulator>::value <= 16) {
|
||||
scope = 3;
|
||||
}
|
||||
else {
|
||||
scope = 5;
|
||||
}
|
||||
}
|
||||
else {
|
||||
scope = 8;
|
||||
@@ -280,6 +287,50 @@ public:
|
||||
|
||||
tensor_D_computed.sync_host();
|
||||
|
||||
//
|
||||
// Reference check - support caching results
|
||||
//
|
||||
|
||||
CachedTestKey cached_test_key = CreateCachedConv2dWithReductionTestKey<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
problem_size,
|
||||
alpha,
|
||||
beta,
|
||||
tensor_A.host_view(),
|
||||
tensor_B.host_view(),
|
||||
tensor_C.host_view()
|
||||
);
|
||||
|
||||
//
|
||||
// Look for the cached key
|
||||
//
|
||||
|
||||
bool cached_result_loaded = false;
|
||||
CachedTestResult cached_test_result;
|
||||
|
||||
std::string conv2d_result_cache_name =
|
||||
std::string("cached_results_") + CUTLASS_TARGET_NAME + ".txt";
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
auto cached = cached_results.find(cached_test_key);
|
||||
|
||||
cached_result_loaded = cached.first;
|
||||
if (cached_result_loaded) {
|
||||
cached_test_result = cached.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
|
||||
#if CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED
|
||||
|
||||
cutlass::reference::device::Conv2d<
|
||||
@@ -326,9 +377,33 @@ public:
|
||||
beta);
|
||||
|
||||
#endif
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
cached_test_result.D = TensorHash(tensor_D_reference.host_view());
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
cached_results.append(cached_test_key, cached_test_result);
|
||||
cached_results.write(conv2d_result_cache_name);
|
||||
}
|
||||
} // if (!cached_result_loaded)
|
||||
|
||||
|
||||
uint32_t tensor_D_hash = TensorHash(tensor_D_computed.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
passed = (tensor_D_hash == cached_test_result.D);
|
||||
|
||||
EXPECT_EQ(tensor_D_hash, cached_test_result.D)
|
||||
<< "Hash-based comparison failed for key:" << "\n" << cached_test_key << "\n";
|
||||
}
|
||||
else {
|
||||
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(passed);
|
||||
|
||||
|
||||
@@ -67,7 +67,8 @@ TEST(SM80_Device_Conv3d_Dgrad_Analytic_ImplicitGemm_tf32ndhwc_tf32ndhwc_f32ndhwc
|
||||
>,
|
||||
cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>,
|
||||
3,
|
||||
cutlass::arch::OpMultiplyAdd
|
||||
cutlass::arch::OpMultiplyAdd,
|
||||
cutlass::conv::IteratorAlgorithm::kAnalytic
|
||||
>::Kernel;
|
||||
|
||||
using Conv3dDgrad = cutlass::conv::device::ImplicitGemmConvolution<Conv3dDgradKernel>;
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
#include "conv3d_problems.h"
|
||||
#include "cutlass/core_io.h"
|
||||
|
||||
#include "cache_testbed_output.h"
|
||||
|
||||
namespace test {
|
||||
namespace conv {
|
||||
namespace device {
|
||||
@@ -321,6 +323,50 @@ public:
|
||||
|
||||
tensor_D_computed.sync_host();
|
||||
|
||||
//
|
||||
// Reference check - support caching results
|
||||
//
|
||||
|
||||
CachedTestKey cached_test_key = CreateCachedConv3dTestKey<
|
||||
ElementA, LayoutA,
|
||||
ElementB, LayoutB,
|
||||
ElementC, LayoutC,
|
||||
ElementAccumulator,
|
||||
ElementCompute
|
||||
>(
|
||||
kConvolutionalOperator,
|
||||
problem_size,
|
||||
alpha,
|
||||
beta,
|
||||
tensor_A.host_view(),
|
||||
tensor_B.host_view(),
|
||||
tensor_C.host_view()
|
||||
);
|
||||
|
||||
//
|
||||
// Look for the cached key
|
||||
//
|
||||
|
||||
bool cached_result_loaded = false;
|
||||
CachedTestResult cached_test_result;
|
||||
|
||||
std::string conv2d_result_cache_name =
|
||||
std::string("cached_results_") + CUTLASS_TARGET_NAME + ".txt";
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
auto cached = cached_results.find(cached_test_key);
|
||||
|
||||
cached_result_loaded = cached.first;
|
||||
if (cached_result_loaded) {
|
||||
cached_test_result = cached.second;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
|
||||
#if CUTLASS_CONV_TEST_UNIT_REFERENCE_DEVICE_ENABLED
|
||||
|
||||
cutlass::reference::device::Conv3d<
|
||||
@@ -368,10 +414,32 @@ public:
|
||||
);
|
||||
#endif
|
||||
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
|
||||
cached_test_result.D = TensorHash(tensor_D_reference.host_view());
|
||||
|
||||
CachedTestResultListing cached_results(conv2d_result_cache_name);
|
||||
|
||||
cached_results.append(cached_test_key, cached_test_result);
|
||||
cached_results.write(conv2d_result_cache_name);
|
||||
}
|
||||
} // if (!cached_result_loaded)
|
||||
|
||||
uint32_t tensor_D_hash = TensorHash(tensor_D_computed.host_view());
|
||||
|
||||
if (CUTLASS_TEST_ENABLE_CACHED_RESULTS) {
|
||||
passed = (tensor_D_hash == cached_test_result.D);
|
||||
|
||||
EXPECT_EQ(tensor_D_hash, cached_test_result.D)
|
||||
<< "Hash-based comparison failed for key:" << "\n" << cached_test_key << "\n";
|
||||
}
|
||||
else {
|
||||
|
||||
passed = cutlass::reference::host::TensorEquals(
|
||||
tensor_D_computed.host_view(),
|
||||
tensor_D_reference.host_view());
|
||||
}
|
||||
|
||||
EXPECT_TRUE(passed);
|
||||
|
||||
if (!passed) {
|
||||
@@ -422,9 +490,19 @@ public:
|
||||
results
|
||||
<< "\nA:\n" << tensor_A.host_view() << "\n"
|
||||
<< "\nB:\n" << tensor_B.host_view() << "\n"
|
||||
<< "\nC:\n" << tensor_C.host_view() << "\n"
|
||||
<< "\nD reference:\n" << tensor_D_reference.host_view() << "\n"
|
||||
<< "\nD computed:\n" << tensor_D_computed.host_view() << "\n";
|
||||
<< "\nC:\n" << tensor_C.host_view() << "\n";
|
||||
|
||||
|
||||
results << "\nD reference (hash: " << cached_test_result.D << ")\n";
|
||||
|
||||
if (!cached_result_loaded) {
|
||||
results
|
||||
<< tensor_D_reference.host_view() << "\n";
|
||||
}
|
||||
|
||||
results
|
||||
<< "\nD computed (hash: " << tensor_D_hash << ")\n"
|
||||
<< tensor_D_computed.host_view() << "\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user