CUTLASS 3.2.1 (#1113)
* Updates for 3.2.1 release. * Minor fix in gemm op profiler for raster order. * Add scheduler mapping for raster order in the kernels.
This commit is contained in:
660
test/python/cutlass/conv2d/conv2d_problem_sizes.py
Normal file
660
test/python/cutlass/conv2d/conv2d_problem_sizes.py
Normal file
@@ -0,0 +1,660 @@
|
||||
#################################################################################################
|
||||
#
|
||||
# Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. 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.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||||
#
|
||||
#################################################################################################
|
||||
|
||||
"""
|
||||
Utilities for defining Conv2D problem sizes for testing.
|
||||
|
||||
This file was ported from the C++ version in test/unit/conv/device/conv2d_problems.h
|
||||
"""
|
||||
|
||||
import cutlass
|
||||
from cutlass import ConvMode
|
||||
from cutlass.shape import Conv2DProblemSize
|
||||
|
||||
|
||||
class TestbedConv2dProblemSizes:
|
||||
def __init__(self, minimum_channel_size: int):
|
||||
conv2d_default_sizes = self.initialize_conv2d_default_sizes(minimum_channel_size)
|
||||
conv2d_rigorous_sizes = self.initialize_conv2d_rigorous_sizes(minimum_channel_size)
|
||||
conv2d_resnet50_sizes = self.initialize_conv2d_resnet50_sizes(1)
|
||||
conv2d_resnet50_sizes_perf = self.initialize_conv2d_resnet50_sizes(34)
|
||||
grouped_sizes = self.initialize_conv2d_grouped_sizes()
|
||||
|
||||
# Filter all problems
|
||||
self.all = []
|
||||
for size_list in [conv2d_default_sizes, conv2d_rigorous_sizes, conv2d_resnet50_sizes, conv2d_resnet50_sizes_perf, grouped_sizes]:
|
||||
for size in size_list:
|
||||
if (size.C // size.groups) % minimum_channel_size == 0:
|
||||
self.all.append(size)
|
||||
|
||||
|
||||
def initialize_conv2d_default_sizes(self, minimum_channel_size):
|
||||
# Small input size x stride (1,1)
|
||||
# C < CTA::K and non-multiples of CTA::K. Typical CTA::K = {32, 64}
|
||||
|
||||
conv2d_default_sizes = []
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 1, 1, minimum_channel_size,
|
||||
8, 1, 1, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 1, 8, minimum_channel_size,
|
||||
8, 1, 3, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 7, 8, minimum_channel_size,
|
||||
8, 3, 3, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 7, 9, minimum_channel_size,
|
||||
8, 4, 4, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
2, 7, 9, minimum_channel_size,
|
||||
8, 5, 5, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
3, 7, 9, minimum_channel_size,
|
||||
8, 6, 5, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
3, 7, 9, minimum_channel_size,
|
||||
8, 6, 6, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
3, 7, 9, minimum_channel_size,
|
||||
8, 7, 7, minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
##############################################
|
||||
# Small input size x stride (2,2)
|
||||
# C < CTA::K and non-multiples of CTA::K. Typical CTA::K = {32, 64}
|
||||
##############################################
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 11, 7, minimum_channel_size,
|
||||
8, 1, 1, minimum_channel_size,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 11, 7, minimum_channel_size,
|
||||
8, 3, 3, minimum_channel_size,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 13, 11, minimum_channel_size,
|
||||
8, 1, 1, minimum_channel_size,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 17, 19, minimum_channel_size,
|
||||
16, 2, 2, minimum_channel_size,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 23, 5, minimum_channel_size,
|
||||
16, 3, 3, minimum_channel_size,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 13, 17, 8,
|
||||
24, 3, 3, 8,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 23, 21, 8,
|
||||
24, 3, 3, 8,
|
||||
1, 1,
|
||||
3, 3,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 20, 24, 8,
|
||||
40, 3, 3, 8,
|
||||
3, 3,
|
||||
3, 3,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
##########################################
|
||||
# Medium input size (1x16x16x128), filter size (1x1, 2x2, 3x3, 5x5), stride (1, 1)
|
||||
##########################################
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 15, 19, 160,
|
||||
224, 1, 1, 160,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 19, 37, 160,
|
||||
224, 3, 3, 160,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 16, 16, 160,
|
||||
224, 2, 3, 160,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 23, 21, 128,
|
||||
224, 3, 3, 128,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 29, 37, 160,
|
||||
224, 5, 5, 160,
|
||||
2, 2,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
##########################################
|
||||
# C > CTA::K and non-multiples of CTA::K. Typical CTA::K = {32, 64}
|
||||
##########################################
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 15, 19, 32 + minimum_channel_size,
|
||||
96, 3, 3, 32 + minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 16, 24, 64 + minimum_channel_size,
|
||||
96, 3, 3, 64 + minimum_channel_size,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
##########################################
|
||||
# Medium input size, filter size (1x1, 3,x3, 5x5, 7x7), stride (2, 2)
|
||||
##########################################
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 13, 16, 288,
|
||||
160, 5, 5, 288,
|
||||
2, 2,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 55, 51, 256,
|
||||
512, 1, 1, 256,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 71, 80, 32,
|
||||
64, 5, 5, 32,
|
||||
2, 2,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 224, 224, 8,
|
||||
64, 7, 7, 8,
|
||||
3, 3,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
##########################################
|
||||
# Medium input size stride (3, 3), filter (3, 3), non-default padding
|
||||
##########################################
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 27, 23, 256,
|
||||
512, 3, 3, 256,
|
||||
0, 0,
|
||||
3, 3,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
##########################################
|
||||
# Medium input size padding > stride, asymmetric filter, padding and striding
|
||||
##########################################
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 27, 31, 256,
|
||||
512, 3, 3, 256,
|
||||
5, 7,
|
||||
3, 4,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 27, 35, 256,
|
||||
512, 7, 5, 256,
|
||||
11, 7,
|
||||
3, 5,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
##########################################
|
||||
# Medium input size *mixed* stride (1, 2) and (2, 1),
|
||||
# filter (3, 3), default padding
|
||||
##########################################
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 27, 27, 256,
|
||||
512, 3, 3, 256,
|
||||
1, 1,
|
||||
1, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 27, 27, 256,
|
||||
512, 3, 3, 256,
|
||||
1, 1,
|
||||
2, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
######################################/
|
||||
# Additional input size
|
||||
######################################/
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
3, 28, 28, 256,
|
||||
256, 2, 2, 256,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
1, 32, 32, 16,
|
||||
32, 3, 3, 16,
|
||||
1, 1,
|
||||
6, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
32, 24, 32, 32,
|
||||
32, 1, 2, 32,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_default_sizes.append(Conv2DProblemSize(
|
||||
4, 2, 3, 256,
|
||||
328, 3, 5, 256,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
return conv2d_default_sizes
|
||||
|
||||
# Add a few large and rigorous convolution problem sizes
|
||||
def initialize_conv2d_rigorous_sizes(self, minimum_channel_size):
|
||||
sizes = []
|
||||
if False:
|
||||
sizes.append(Conv2DProblemSize.from_sizes(
|
||||
(1, 124, 224, 2 * minimum_channel_size),
|
||||
(24, 7, 7, 2 * minimum_channel_size),
|
||||
))
|
||||
|
||||
sizes.append(Conv2DProblemSize.from_sizes(
|
||||
(1, 233, 35, minimum_channel_size),
|
||||
(24, 7, 5, minimum_channel_size),
|
||||
))
|
||||
return sizes
|
||||
|
||||
# Add resent50 layers to unit testing sizes
|
||||
def initialize_conv2d_resnet50_sizes(self, batch_size):
|
||||
conv2d_problem_vector = []
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 56, 56, 64,
|
||||
256, 1, 1, 64,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 56, 56, 64,
|
||||
64, 1, 1, 64,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 56, 56, 64,
|
||||
64, 3, 3, 64,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 56, 56, 256,
|
||||
64, 1, 1, 256,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 56, 56, 256,
|
||||
512, 1, 1, 256,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 56, 56, 256,
|
||||
128, 1, 1, 256,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 28, 28, 128,
|
||||
128, 3, 3, 128,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 28, 28, 128,
|
||||
512, 1, 1, 128,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 28, 28, 512,
|
||||
128, 1, 1, 512,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 28, 28, 512,
|
||||
1024, 1, 1, 512,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 28, 28, 512,
|
||||
256, 1, 1, 512,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 14, 14, 256,
|
||||
256, 3, 3, 256,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 14, 14, 256,
|
||||
1024, 1, 1, 256,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 14, 14, 1024,
|
||||
256, 1, 1, 1024,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 14, 14, 1024,
|
||||
2048, 1, 1, 1024,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 14, 14, 1024,
|
||||
512, 1, 1, 1024,
|
||||
0, 0,
|
||||
2, 2,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 7, 7, 512,
|
||||
512, 3, 3, 512,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 7, 7, 512,
|
||||
2048, 1, 1, 512,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
conv2d_problem_vector.append(Conv2DProblemSize(
|
||||
batch_size, 7, 7, 2048,
|
||||
512, 1, 1, 2048,
|
||||
0, 0,
|
||||
1, 1,
|
||||
1, 1,
|
||||
))
|
||||
|
||||
return conv2d_problem_vector
|
||||
|
||||
def initialize_conv2d_grouped_sizes(self):
|
||||
threadblock_n = 128
|
||||
threadblock_k = 32
|
||||
|
||||
sizes = []
|
||||
##########################################
|
||||
# One group calculated by one or multiple CTAs: k_per_group % CTA::N = 0
|
||||
# One CTA calculates a single group
|
||||
##########################################
|
||||
for cta_per_group_k in range(1, 4):
|
||||
for groups in range(2, 5):
|
||||
conv_k = cta_per_group_k * threadblock_n * groups
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 8, 8, threadblock_k * 2 * groups,
|
||||
conv_k, 3, 3, threadblock_k * 2,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
groups
|
||||
))
|
||||
|
||||
# Partial gemm_k: k_per_group == CTA::N && channels_per_group < CTA::K
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 8, 8, threadblock_k,
|
||||
threadblock_n * 2, 3, 3, threadblock_k // 2,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
2
|
||||
))
|
||||
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 56, 56, 696,
|
||||
768, 3, 3, 232,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
3
|
||||
))
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 14, 14, 1392,
|
||||
1536, 3, 3, 232,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
3
|
||||
))
|
||||
|
||||
##########################################
|
||||
# One CTA calculate multiple groups: CTA::N % k_per_group = 0
|
||||
##########################################
|
||||
|
||||
# 2 groups per CTA
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 8, 8, threadblock_k * 4,
|
||||
threadblock_n, 3, 3, threadblock_k * 2,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
2
|
||||
))
|
||||
|
||||
# 2 groups per CTA and partial gemm_k
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 8, 8, threadblock_k,
|
||||
threadblock_n, 3, 3, threadblock_k // 2,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
2
|
||||
))
|
||||
|
||||
# 4 groups per CTA
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 8, 8, threadblock_k * 8,
|
||||
threadblock_n // 2, 3, 3, threadblock_k * 2,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
4
|
||||
))
|
||||
|
||||
# 4 groups per CTA and partial gemm_k
|
||||
sizes.append(Conv2DProblemSize(
|
||||
1, 8, 8, threadblock_k * 2,
|
||||
threadblock_n // 2, 3, 3, threadblock_k // 2,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1,
|
||||
4
|
||||
))
|
||||
|
||||
return sizes
|
||||
146
test/python/cutlass/conv2d/conv2d_sm80.py
Normal file
146
test/python/cutlass/conv2d/conv2d_sm80.py
Normal file
@@ -0,0 +1,146 @@
|
||||
#################################################################################################
|
||||
#
|
||||
# Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. 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.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||||
#
|
||||
#################################################################################################
|
||||
|
||||
"""
|
||||
Low-level functionality tests for Conv2d opreations on SM80
|
||||
"""
|
||||
|
||||
import logging
|
||||
import unittest
|
||||
|
||||
import cutlass
|
||||
from cutlass.backend.utils.device import device_cc
|
||||
|
||||
from conv2d_test_utils import *
|
||||
|
||||
|
||||
cutlass.set_log_level(logging.WARNING)
|
||||
cc = 80
|
||||
|
||||
|
||||
@unittest.skipIf(device_cc() < cc, 'Device compute capability is invalid for SM80 tests.')
|
||||
class Conv2dSm80(unittest.TestCase):
|
||||
"""
|
||||
Wrapper class to which tests will be added dynamically in __main__
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
conv_problems = get_conv_problems()
|
||||
|
||||
|
||||
# Tests for optimized & analytic
|
||||
for conv_kind in ["fprop", "wgrad", "dgrad"]:
|
||||
# F16, simt
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="simt", threadblock_shape=[128, 128, 8],
|
||||
warp_count=[4, 2, 1], stages=2, instruction_shape=[1, 1, 1])
|
||||
# F16, tensor op
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 64],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 16])
|
||||
# F16, tensor op, analytic iterator
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f16, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 64],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 16], iterator_algorithm="analytic")
|
||||
# F16, tensor op, f32 output
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f32,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 64],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 16])
|
||||
# F16, tensor op, different tile description
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 64, 32],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 8])
|
||||
# F32, simt
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f32, cutlass.DataType.f32, cutlass.DataType.f32,
|
||||
opclass="simt", threadblock_shape=[128, 128, 8],
|
||||
warp_count=[4, 2, 1], stages=4, instruction_shape=[1, 1, 1])
|
||||
# Tf32, tensorop
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f32, cutlass.DataType.f32, cutlass.DataType.f32,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 16],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 8]
|
||||
)
|
||||
# Split-K
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 64],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 16], split_k_mode="serial",
|
||||
split_k_slices=2)
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 64],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 16], split_k_mode="parallel",
|
||||
split_k_slices=5)
|
||||
# Swizzling functor
|
||||
add_test(
|
||||
Conv2dSm80, cc, conv_kind, conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 64, 32],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 8], swizzle=4)
|
||||
|
||||
# Tests for few channels and fixed channels
|
||||
# F16, tensor op, few channels
|
||||
for c, tb, stage, inst in zip([2, 1],
|
||||
[[128, 128, 64], [128, 128, 32]],
|
||||
[3, 2],
|
||||
[[16, 8, 16], [16, 8, 8]]):
|
||||
add_test(
|
||||
Conv2dSm80, cc, "fprop", conv2d_few_channel_problemsizes(c), cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=tb,
|
||||
warp_count=[2, 2, 1], stages=stage, instruction_shape=inst, iterator_algorithm="few_channels"
|
||||
)
|
||||
# F16, tensor op, fixed channels
|
||||
for c in [8, 4, 2]:
|
||||
add_test(
|
||||
Conv2dSm80, cc, "fprop", conv2d_few_channel_problemsizes(c), cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 64],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 16], iterator_algorithm="fixed_channels"
|
||||
)
|
||||
|
||||
# Test activations
|
||||
for activation in ["relu", "leaky_relu"]:
|
||||
for split_k_mode, split_k_slices in zip(["parallel", "serial", "parallel"], [1, 7, 5]):
|
||||
add_test(
|
||||
Conv2dSm80, cc, "fprop", conv_problems, cutlass.DataType.f16, cutlass.DataType.f32, cutlass.DataType.f16,
|
||||
opclass="tensor_op", threadblock_shape=[128, 128, 64],
|
||||
warp_count=[2, 2, 1], stages=3, instruction_shape=[16, 8, 16], split_k_mode=split_k_mode,
|
||||
split_k_slices=split_k_slices, activation=activation)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
425
test/python/cutlass/conv2d/conv2d_test_utils.py
Normal file
425
test/python/cutlass/conv2d/conv2d_test_utils.py
Normal file
@@ -0,0 +1,425 @@
|
||||
#################################################################################################
|
||||
#
|
||||
# Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. 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.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||||
#
|
||||
#################################################################################################
|
||||
|
||||
"""
|
||||
Utility functions for Conv2d tests.
|
||||
"""
|
||||
|
||||
import torch
|
||||
|
||||
import cutlass
|
||||
from cutlass import (
|
||||
ConvKind,
|
||||
ConvMode,
|
||||
DataType,
|
||||
DataTypeNames,
|
||||
EpilogueScheduleSuffixes,
|
||||
KernelScheduleSuffixes,
|
||||
LayoutType,
|
||||
OpcodeClassNames,
|
||||
ShortDataTypeNames,
|
||||
ShortLayoutTypeNames,
|
||||
SplitKMode,
|
||||
)
|
||||
from cutlass.backend.utils.software import SubstituteTemplate
|
||||
from cutlass.shape import Conv2DProblemSize
|
||||
from cutlass.utils.datatypes import numpy_type, torch_type
|
||||
|
||||
from conv2d_problem_sizes import TestbedConv2dProblemSizes
|
||||
|
||||
|
||||
def get_name_conv2d(
|
||||
arch,
|
||||
conv_kind,
|
||||
element,
|
||||
element_accumulator,
|
||||
element_output,
|
||||
opclass,
|
||||
threadblock_shape,
|
||||
warp_count,
|
||||
instruction_shape,
|
||||
stages,
|
||||
iterator_algorithm,
|
||||
swizzle,
|
||||
split_k_mode,
|
||||
split_k_slices,
|
||||
activation
|
||||
):
|
||||
"""
|
||||
Generates a procedural name for a test case for conv2d
|
||||
|
||||
:param arch: compute capability of kernel being generated
|
||||
:type arch: int
|
||||
:param conv_kind: the convolution type (i.e. fprop, dgrad, wgrad)
|
||||
:type conv_kind: str
|
||||
:param iterator_algorithm: the iterator algorithm applied
|
||||
:type iterator_algorithm: cutlass_library.library.IteratorAlgorithm
|
||||
:param element_a: data type of operand A
|
||||
:param element_b: data type of operand B
|
||||
:param element_c: data type of operand C
|
||||
:param element_accumulator: data type used in accumulation
|
||||
:param opclass: class of operation being performed (e.g., SIMT, Tensor Core)
|
||||
:type opclass: cutlass.OpcodeClass
|
||||
:param threadblock_shape: indexable container of dimensions of threadblock tiles
|
||||
:param stages: number of pipeline stages to use in the kernel
|
||||
:type stages: int
|
||||
:param stride_support: stride support of dgrad
|
||||
:param alignment: int
|
||||
:type alignment: int
|
||||
|
||||
:return: str
|
||||
"""
|
||||
if iterator_algorithm is None:
|
||||
iterator_algorithm = "AUTO"
|
||||
if swizzle is None:
|
||||
swizzle = 1
|
||||
name_format = "test_SM${arch}_Device_Conv2d_${conv_kind}_${iter_alg}_ImplicitGemm_${eA}nhwc_${eB}nhwc_${eC}nhwc_${opclass}_${acc}_${tbM}x${tbN}x${tbK}_${wM}x${wN}x${wK}_${IM}${IN}${IK}_stage${stages}_swizzle${swizzle}_${split_k_mode}${split_k_slices}_${activation}"
|
||||
|
||||
return SubstituteTemplate(
|
||||
name_format,
|
||||
{
|
||||
"arch": str(arch),
|
||||
"conv_kind": conv_kind,
|
||||
"iter_alg": iterator_algorithm,
|
||||
"eA": DataTypeNames[element],
|
||||
"eB": DataTypeNames[element],
|
||||
"eC": DataTypeNames[element_output],
|
||||
"opclass": opclass,
|
||||
"acc": DataTypeNames[element_accumulator],
|
||||
"tbM": str(threadblock_shape[0]),
|
||||
"tbN": str(threadblock_shape[1]),
|
||||
"tbK": str(threadblock_shape[2]),
|
||||
"wM": str(threadblock_shape[0] // warp_count[0]),
|
||||
"wN": str(threadblock_shape[1] // warp_count[1]),
|
||||
"wK": str(threadblock_shape[2] // warp_count[2]),
|
||||
"IM": str(instruction_shape[0]),
|
||||
"IN": str(instruction_shape[1]),
|
||||
"IK": str(instruction_shape[2]),
|
||||
"stages": str(stages),
|
||||
"swizzle": str(swizzle),
|
||||
"split_k_mode": split_k_mode,
|
||||
"split_k_slices": str(split_k_slices),
|
||||
"activation": activation
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def conv2d_few_channel_problemsizes(channels):
|
||||
problem_sizes = [
|
||||
Conv2DProblemSize(
|
||||
1, 8, 8, channels,
|
||||
16, 3, 3, channels,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 16, 16, channels,
|
||||
16, 3, 3, channels,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 16, 16, channels,
|
||||
16, 7, 7, channels,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 224, 224, channels,
|
||||
32, 7, 7, channels,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 224, 224, channels,
|
||||
64, 7, 7, channels,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 224, 224, channels,
|
||||
64, 5, 5, channels,
|
||||
1, 1,
|
||||
1, 1,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 224, 224, channels,
|
||||
64, 5, 5, channels,
|
||||
1, 1,
|
||||
2, 2,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
]
|
||||
|
||||
return problem_sizes
|
||||
|
||||
|
||||
def validate_problem_size(ps, conv_kind, split_k_slices):
|
||||
P = (ps.H + 2 * ps.pad_h - ps.dilation_h * (ps.R - 1) - 1) // ps.stride_h + 1
|
||||
Q = (ps.W + 2 * ps.pad_w - ps.dilation_w * (ps.S - 1) - 1) // ps.stride_w + 1
|
||||
if P != ps.P or Q != ps.Q:
|
||||
return False
|
||||
|
||||
# Split-K (serial or parallel) is not supported for strided dgrad
|
||||
if conv_kind == "dgrad" and split_k_slices > 1 and (ps.stride_h > 1 or ps.stride_w > 1):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
class Conv2dLauncherFrontend:
|
||||
def __init__(self, plan: cutlass.Conv2d, seed: int = 80, backend="numpy"):
|
||||
self.operation = plan
|
||||
self.conv_kind = plan.conv_kind
|
||||
self.seed = seed
|
||||
self.backend = backend
|
||||
|
||||
self.dtype_A = plan._element_a
|
||||
self.dtype_B = plan._element_b
|
||||
self.dtype_C = plan._element_c
|
||||
self.dtype_acc = plan._element_accumulator
|
||||
self.layout_A = LayoutType.TensorNHWC
|
||||
self.layout_B = LayoutType.TensorNHWC
|
||||
self.layout_C = LayoutType.TensorNHWC
|
||||
self.layout_D = LayoutType.TensorNHWC
|
||||
|
||||
self.element_compute = DataType.f32
|
||||
|
||||
if self.dtype_A in [cutlass.DataType.f16, cutlass.DataType.bf16]:
|
||||
self.rand_max = 1
|
||||
else:
|
||||
self.rand_max = 4
|
||||
self.activation = plan.activation
|
||||
|
||||
def uniform_init(self, size, dtype):
|
||||
tensor = torch.ceil(
|
||||
torch.empty(size=size, dtype=torch_type(dtype), device="cuda").uniform_(-self.rand_max - 0.5, self.rand_max - 0.5)
|
||||
).to(memory_format=torch.channels_last)
|
||||
return tensor
|
||||
|
||||
def reference(self, ps, A, B, C, alpha, beta, activation):
|
||||
if self.conv_kind == ConvKind.Fprop:
|
||||
torch_result = alpha * torch.ops.aten.conv2d(
|
||||
A,
|
||||
B,
|
||||
stride=(ps.stride_h, ps.stride_w),
|
||||
padding=(ps.pad_h, ps.pad_w),
|
||||
dilation=(ps.dilation_h, ps.dilation_w)
|
||||
) + beta * C
|
||||
elif self.conv_kind == ConvKind.Dgrad:
|
||||
torch_result = alpha * torch.nn.grad.conv2d_input(
|
||||
(ps.N, ps.C, ps.H, ps.W),
|
||||
B,
|
||||
A,
|
||||
padding=(ps.pad_h, ps.pad_w),
|
||||
stride=(ps.stride_h, ps.stride_w)
|
||||
) + beta * C
|
||||
elif self.conv_kind == ConvKind.Wgrad:
|
||||
torch_result = alpha * torch.nn.grad.conv2d_weight(
|
||||
B,
|
||||
(ps.K, ps.C, ps.R, ps.S),
|
||||
A,
|
||||
padding=(ps.pad_h, ps.pad_w),
|
||||
stride=(ps.stride_h, ps.stride_w)
|
||||
) + beta * C
|
||||
else:
|
||||
raise Exception(f"Conv kind {self.conv_kind} is currently unsupported.")
|
||||
|
||||
if activation == cutlass.backend.epilogue.relu:
|
||||
torch_result = torch.nn.functional.relu(torch_result)
|
||||
elif activation == cutlass.backend.epilogue.leaky_relu:
|
||||
torch_result = torch.nn.functional.leaky_relu(torch_result, 0.5)
|
||||
return torch_result
|
||||
|
||||
def run(self, ps, split_k_mode=SplitKMode.Serial, split_k_slices=1, alpha=1.0, beta=0.0):
|
||||
if self.conv_kind == ConvKind.Fprop:
|
||||
tensor_A_size = (ps.N, ps.C, ps.H, ps.W)
|
||||
tensor_B_size = (ps.K, ps.C, ps.R, ps.S)
|
||||
tensor_C_size = (ps.N, ps.K, ps.P, ps.Q)
|
||||
elif self.conv_kind == ConvKind.Dgrad:
|
||||
tensor_A_size = (ps.N, ps.K, ps.P, ps.Q)
|
||||
tensor_B_size = (ps.K, ps.C, ps.R, ps.S)
|
||||
tensor_C_size = (ps.N, ps.C, ps.H, ps.W)
|
||||
elif self.conv_kind == ConvKind.Wgrad:
|
||||
tensor_A_size = (ps.N, ps.K, ps.P, ps.Q)
|
||||
tensor_B_size = (ps.N, ps.C, ps.H, ps.W)
|
||||
tensor_C_size = (ps.K, ps.C, ps.R, ps.S)
|
||||
else:
|
||||
raise Exception(f"Conv kind {self.conv_kind} is not supported")
|
||||
|
||||
torch.manual_seed(self.seed)
|
||||
|
||||
tensor_A = self.uniform_init(size=tensor_A_size, dtype=self.dtype_A)
|
||||
tensor_B = self.uniform_init(size=tensor_B_size, dtype=self.dtype_B)
|
||||
tensor_C = self.uniform_init(size=tensor_C_size, dtype=self.dtype_C)
|
||||
tensor_D = torch.zeros_like(tensor_C).to(memory_format=torch.channels_last)
|
||||
self.operation.run(tensor_A, tensor_B, tensor_C, tensor_D,
|
||||
stride=(ps.stride_h, ps.stride_w),
|
||||
padding=(ps.pad_h, ps.pad_w),
|
||||
dilation=(ps.dilation_h, ps.dilation_w),
|
||||
alpha=alpha, beta=beta,
|
||||
split_k=(split_k_mode, split_k_slices))
|
||||
|
||||
tensor_D_ref = self.reference(ps, tensor_A, tensor_B, tensor_C, alpha, beta, self.activation)
|
||||
|
||||
torch.cuda.synchronize()
|
||||
passed = torch.equal(tensor_D, tensor_D_ref)
|
||||
|
||||
return passed
|
||||
|
||||
|
||||
def add_test(
|
||||
cls,
|
||||
cc,
|
||||
conv_kind,
|
||||
problem_sizes,
|
||||
element,
|
||||
element_accumulator,
|
||||
element_output,
|
||||
opclass,
|
||||
threadblock_shape,
|
||||
warp_count,
|
||||
instruction_shape,
|
||||
stages,
|
||||
iterator_algorithm=None,
|
||||
swizzle=None,
|
||||
split_k_mode="serial",
|
||||
split_k_slices=1,
|
||||
activation = "identity"
|
||||
):
|
||||
"""Create a test-running function with the given specification"""
|
||||
test_name = get_name_conv2d(
|
||||
cc, conv_kind, element, element_accumulator,
|
||||
element_output, opclass, threadblock_shape, warp_count, instruction_shape, stages,
|
||||
iterator_algorithm, swizzle, split_k_mode, split_k_slices, activation)
|
||||
|
||||
def run(self):
|
||||
# Create the plan
|
||||
plan = cutlass.Conv2d(
|
||||
kind=conv_kind,
|
||||
element=element,
|
||||
element_accumulator=element_accumulator,
|
||||
element_C=element_output,
|
||||
element_D=element_output
|
||||
)
|
||||
|
||||
# Set the opclass
|
||||
plan.opclass = opclass
|
||||
# Set the tile description
|
||||
td = {
|
||||
"threadblock_shape": threadblock_shape,
|
||||
"warp_count": warp_count,
|
||||
"stages": stages,
|
||||
"instruction_shape": instruction_shape,
|
||||
}
|
||||
|
||||
plan.tile_description = td
|
||||
# Set iterator algorithm
|
||||
if iterator_algorithm is not None:
|
||||
plan.iterator_algorithm = iterator_algorithm
|
||||
# Set swizzling functor
|
||||
if swizzle is not None:
|
||||
plan.swizzling_stride = swizzle
|
||||
|
||||
if activation != "identity":
|
||||
if activation == "leaky_relu":
|
||||
plan.activation = (cutlass.epilogue.leaky_relu, 0.5)
|
||||
else:
|
||||
plan.activation = getattr(cutlass.epilogue, activation)
|
||||
|
||||
conv2d_launcher = Conv2dLauncherFrontend(plan, 80, backend="torch")
|
||||
|
||||
for ps in problem_sizes:
|
||||
if not validate_problem_size(ps, conv_kind, split_k_slices): continue
|
||||
|
||||
self.assertTrue(conv2d_launcher.run(ps, split_k_mode, split_k_slices, 1.0, 2.0))
|
||||
|
||||
setattr(cls, test_name, run)
|
||||
|
||||
return run
|
||||
|
||||
|
||||
def get_conv_problems():
|
||||
# 64: minimum channel size
|
||||
conv_problems = TestbedConv2dProblemSizes(64).all
|
||||
|
||||
# Insert alignment 4 & 2 tests
|
||||
conv_problems += [
|
||||
Conv2DProblemSize(
|
||||
1, 4, 4, 12,
|
||||
8, 3, 3, 12,
|
||||
0, 0,
|
||||
3, 3,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 4, 4, 14,
|
||||
8, 3, 3, 14,
|
||||
0, 0,
|
||||
3, 3,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
Conv2DProblemSize(
|
||||
1, 23, 56, 98,
|
||||
128, 3, 3, 98,
|
||||
4, 5,
|
||||
3, 3,
|
||||
1, 1,
|
||||
ConvMode.CrossCorrelation,
|
||||
1, 1
|
||||
),
|
||||
]
|
||||
|
||||
return conv_problems
|
||||
44
test/python/cutlass/conv2d/run_all_tests.py
Normal file
44
test/python/cutlass/conv2d/run_all_tests.py
Normal file
@@ -0,0 +1,44 @@
|
||||
#################################################################################################
|
||||
#
|
||||
# Copyright (c) 2023 - 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright notice, this
|
||||
# list of conditions and the following disclaimer.
|
||||
#
|
||||
# 2. 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.
|
||||
#
|
||||
# 3. Neither the name of the copyright holder 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 THE COPYRIGHT HOLDER OR CONTRIBUTORS 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.
|
||||
#
|
||||
#################################################################################################
|
||||
|
||||
import pathlib
|
||||
import unittest
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
loader = unittest.TestLoader()
|
||||
script_dir = str(pathlib.Path(__file__).parent.resolve()) + '/'
|
||||
tests = loader.discover(script_dir, 'conv2d_*.py')
|
||||
testRunner = unittest.runner.TextTestRunner()
|
||||
results = testRunner.run(tests)
|
||||
if not results.wasSuccessful():
|
||||
raise Exception('Test cases failed')
|
||||
Reference in New Issue
Block a user