update 3.8 v2 (#2112)
* update 3.8 v2 * update 3.8 --------- Co-authored-by: yuzhai <yuzhai@nvidia.com>
This commit is contained in:
@@ -45,7 +45,7 @@
|
||||
CTA rasterization direction and swizzle pattern impact cross-CTA locality of accesses. By tuning we can
|
||||
improve performance.
|
||||
Examples:
|
||||
$ ./examples/64_hopper_fp8_warp_specialized_gemm_with_groupwise_scaling/64_hopper_fp8_warp_specialized_gemm_with_groupwise_scaling \
|
||||
$ ./examples/67_hopper_fp8_warp_specialized_gemm_with_blockwise_scaling/67_hopper_fp8_warp_specialized_gemm_with_groupwise_scaling \
|
||||
--m=2816 --n=3072 --k=16384 \
|
||||
--save_aux=false --save_amax=false \
|
||||
--device_scale=false --raster=h --swizzle=2
|
||||
@@ -119,22 +119,56 @@ using ElementBias = float;
|
||||
using ElementAccumulator = float; // Element type for internal accumulation
|
||||
using ElementBlockScale = float; // Element type for blockscaling during accumulation
|
||||
using ElementCompute = float; // Element type for epilogue computation
|
||||
using ArchTag = cutlass::arch::Sm90; // Tag indicating the minimum SM that supports the intended feature
|
||||
using OperatorClass = cutlass::arch::OpClassTensorOp; // Operator class tag
|
||||
using TileShape = Shape<_128,_128,_128>; // Threadblock-level tile size
|
||||
using ClusterShape = Shape<_1,_2,_1>; // Shape of the threadblocks in a cluster
|
||||
|
||||
constexpr int ScaleMsPerTile = 2;
|
||||
constexpr int ScaleGranularityM = size<0>(TileShape{}) / ScaleMsPerTile;
|
||||
using TileShape_ = Shape<_128,_128,_128>; // This one is just to make the compiler happy with verify()...
|
||||
|
||||
using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecializedCooperativeFP8BlockScaledAccum<ScaleGranularityM>;
|
||||
using EpilogueSchedule = cutlass::epilogue::TmaWarpSpecializedCooperative;
|
||||
// ScaleGranularity{M,N}: number of {rows in A}/{columns in B} that share the same scaling factor
|
||||
// Given TileShape = Shape<_128,_128,_128>:
|
||||
// ScaleGranularityM == 128 and ScaleGranularityN == 128 --> 2Dx2D (the shape of the scaling factor)
|
||||
// ScaleGranularityM == 1 and ScaleGranularityN == 128 --> 1Dx2D scaling
|
||||
// ScaleGranularityM == 128 and ScaleGranularityN == 1 --> 2Dx1D scaling
|
||||
// ScaleGranularityM == 1 and ScaleGranularityN == 1 --> 1Dx1D scaling
|
||||
template <int ScaleGranularityM_, int ScaleGranularityN_>
|
||||
struct GroupScaleConfig {
|
||||
using ArchTag = cutlass::arch::Sm90; // Tag indicating the minimum SM that supports the intended feature
|
||||
using OperatorClass = cutlass::arch::OpClassTensorOp; // Operator class tag
|
||||
using TileShape = Shape<_128,_128,_128>; // Threadblock-level tile size
|
||||
using ClusterShape = Shape<_1,_2,_1>; // Shape of the threadblocks in a cluster
|
||||
|
||||
using EpilogueTileType = cutlass::epilogue::collective::EpilogueTileAuto;
|
||||
using FusionOperation = cutlass::epilogue::fusion::ScaledLinCombPerRowBiasEltActAmaxAux<
|
||||
static constexpr int ScaleGranularityM = ScaleGranularityM_;
|
||||
static constexpr int ScaleGranularityN = ScaleGranularityN_;
|
||||
static constexpr int ScaleMsPerTile = size<0>(TileShape{}) / ScaleGranularityM;
|
||||
static constexpr int ScaleNsPerTile = size<1>(TileShape{}) / ScaleGranularityN;
|
||||
|
||||
static_assert(size<0>(TileShape{}) == ScaleGranularityM * ScaleMsPerTile,
|
||||
"FP8 scaling granularity must evenly divide tile shape along M.");
|
||||
static_assert(size<1>(TileShape{}) == ScaleGranularityN * ScaleNsPerTile,
|
||||
"FP8 scaling granularity must evenly divide tile shape along N.");
|
||||
|
||||
using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecializedCooperativeFP8BlockScaledAccum<ScaleGranularityM_, ScaleGranularityN_>;
|
||||
using EpilogueSchedule = cutlass::epilogue::TmaWarpSpecializedCooperative;
|
||||
using EpilogueTileType = cutlass::epilogue::collective::EpilogueTileAuto;
|
||||
using FusionOperation = cutlass::epilogue::fusion::ScaledLinCombPerRowBiasEltActAmaxAux<
|
||||
LayoutAux, cutlass::epilogue::thread::ReLU, ElementD, ElementCompute, ElementAux, ElementAmax, ElementBias, ElementC>;
|
||||
};
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
using GroupScale1D1DConfig = GroupScaleConfig< 1, 1>;
|
||||
using GroupScale1D2DConfig = GroupScaleConfig< 1, size<1>(TileShape_{})>;
|
||||
using GroupScale2D1DConfig = GroupScaleConfig<size<0>(TileShape_{}), 1>;
|
||||
using GroupScale2D2DConfig = GroupScaleConfig<size<0>(TileShape_{}), size<1>(TileShape_{})>;
|
||||
|
||||
template <typename ScheduleConfig>
|
||||
struct GroupScaleGemm {
|
||||
using ArchTag = typename ScheduleConfig::ArchTag;
|
||||
using OperatorClass = typename ScheduleConfig::OperatorClass;
|
||||
using TileShape = typename ScheduleConfig::TileShape;
|
||||
using ClusterShape = typename ScheduleConfig::ClusterShape;
|
||||
using KernelSchedule = typename ScheduleConfig::KernelSchedule;
|
||||
using EpilogueSchedule = typename ScheduleConfig::EpilogueSchedule;
|
||||
using EpilogueTileType = typename ScheduleConfig::EpilogueTileType;
|
||||
using FusionOperation = typename ScheduleConfig::FusionOperation;
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
TileShape, ClusterShape,
|
||||
EpilogueTileType,
|
||||
@@ -145,7 +179,7 @@ using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBui
|
||||
FusionOperation
|
||||
>::CollectiveOp;
|
||||
|
||||
using CollectiveMainloopWithBlockWiseScaling = typename cutlass::gemm::collective::CollectiveBuilder<
|
||||
using CollectiveMainloopWithGroupWiseScaling = typename cutlass::gemm::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
ElementA, LayoutA, AlignmentA,
|
||||
ElementB, LayoutB, AlignmentB,
|
||||
@@ -157,24 +191,38 @@ using CollectiveMainloopWithBlockWiseScaling = typename cutlass::gemm::collectiv
|
||||
KernelSchedule
|
||||
>::CollectiveOp;
|
||||
|
||||
using GemmKernel = cutlass::gemm::kernel::GemmUniversal<
|
||||
Shape<int,int,int,int>, // Indicates ProblemShape
|
||||
CollectiveMainloopWithBlockWiseScaling,
|
||||
CollectiveEpilogue
|
||||
>;
|
||||
using GemmKernelDefault = cutlass::gemm::kernel::GemmUniversal<
|
||||
Shape<int,int,int,int>,
|
||||
CollectiveMainloopWithGroupWiseScaling,
|
||||
CollectiveEpilogue
|
||||
>;
|
||||
|
||||
using Gemm = cutlass::gemm::device::GemmUniversalAdapter<GemmKernel>;
|
||||
using GemmKernelStreamK = cutlass::gemm::kernel::GemmUniversal<
|
||||
Shape<int,int,int,int>,
|
||||
CollectiveMainloopWithGroupWiseScaling,
|
||||
CollectiveEpilogue,
|
||||
cutlass::gemm::StreamKScheduler
|
||||
>;
|
||||
|
||||
using GemmDefault = cutlass::gemm::device::GemmUniversalAdapter<GemmKernelDefault>;
|
||||
using GemmStreamK = cutlass::gemm::device::GemmUniversalAdapter<GemmKernelStreamK>;
|
||||
};
|
||||
|
||||
using GroupScale1D1DGemm = GroupScaleGemm<GroupScale1D1DConfig>;
|
||||
using GroupScale1D2DGemm = GroupScaleGemm<GroupScale1D2DConfig>;
|
||||
using GroupScale2D1DGemm = GroupScaleGemm<GroupScale2D1DConfig>;
|
||||
using GroupScale2D2DGemm = GroupScaleGemm<GroupScale2D2DConfig>;
|
||||
|
||||
// Extract information from Gemm kernel.
|
||||
using EpilogueOutputOp = typename Gemm::EpilogueOutputOp;
|
||||
using EpilogueOutputOp = typename GroupScale1D1DGemm::GemmDefault::EpilogueOutputOp;
|
||||
using ElementScalar = typename EpilogueOutputOp::ElementScalar;
|
||||
using ElementAmax = typename EpilogueOutputOp::ElementAmax;
|
||||
using ActivationFunctor = typename EpilogueOutputOp::ActivationFn;
|
||||
|
||||
using StrideA = typename Gemm::GemmKernel::StrideA;
|
||||
using StrideB = typename Gemm::GemmKernel::StrideB;
|
||||
using StrideC = typename Gemm::GemmKernel::StrideC;
|
||||
using StrideD = typename Gemm::GemmKernel::StrideD;
|
||||
using StrideA = typename GroupScale1D1DGemm::GemmDefault::GemmKernel::StrideA;
|
||||
using StrideB = typename GroupScale1D1DGemm::GemmDefault::GemmKernel::StrideB;
|
||||
using StrideC = typename GroupScale1D1DGemm::GemmDefault::GemmKernel::StrideC;
|
||||
using StrideD = typename GroupScale1D1DGemm::GemmDefault::GemmKernel::StrideD;
|
||||
using StrideAux = StrideD;
|
||||
|
||||
constexpr bool IsDFp8 =
|
||||
@@ -185,9 +233,6 @@ constexpr bool IsAuxFp8 =
|
||||
cute::is_same_v<ElementAux, cutlass::float_e4m3_t> or
|
||||
cute::is_same_v<ElementAux, cutlass::float_e5m2_t>;
|
||||
|
||||
static_assert(size<0>(TileShape{}) == ScaleGranularityM * ScaleMsPerTile,
|
||||
"FP8 scaling granularity must evenly divide tile shape along M.");
|
||||
|
||||
static_assert(cute::is_same_v<ElementAccumulator, ElementBlockScale>,
|
||||
"ElementAccumulator and ElementBlockScale should be same datatype");
|
||||
|
||||
@@ -347,13 +392,18 @@ struct Result
|
||||
}
|
||||
|
||||
/// Initialize operands to be used in the GEMM and reference GEMM
|
||||
template <typename GroupScaleConfig>
|
||||
void initialize(const Options<RasterOrderOptions> &options) {
|
||||
|
||||
using TileShape = typename GroupScaleConfig::TileShape;
|
||||
const int ScaleMsPerTile = GroupScaleConfig::ScaleMsPerTile;
|
||||
const int ScaleNsPerTile = GroupScaleConfig::ScaleNsPerTile;
|
||||
|
||||
// Find Group Scaling tensor shapes based on `ScaleGranularityM`, problem shape, and TileShape
|
||||
auto gemm_problem_shape = cute::make_shape(options.m, options.n, options.k);
|
||||
auto blockscale_shape = shape(get<1>(cute::zipped_divide(cute::make_layout(gemm_problem_shape), TileShape{})));
|
||||
auto groupscale_m = cute::get<0>(blockscale_shape) * ScaleMsPerTile; // We need to pad along M in scale tensor of A to prevent illegal memory access.
|
||||
auto blockscale_n = cute::get<1>(blockscale_shape);
|
||||
auto groupscale_n = cute::get<1>(blockscale_shape) * ScaleNsPerTile; // We need to pad along N in scale tensor of A to prevent illegal memory access.
|
||||
auto blockscale_k = cute::get<2>(blockscale_shape);
|
||||
|
||||
stride_A = cutlass::make_cute_packed_stride(StrideA{}, cute::make_shape(options.m, options.k, options.l));
|
||||
@@ -362,18 +412,16 @@ void initialize(const Options<RasterOrderOptions> &options) {
|
||||
stride_D = cutlass::make_cute_packed_stride(StrideD{}, cute::make_shape(options.m, options.n, options.l));
|
||||
stride_aux = stride_D;
|
||||
|
||||
|
||||
|
||||
auto a_coord = cutlass::make_Coord(options.m * options.l, options.k);
|
||||
auto c_coord = cutlass::make_Coord(options.m * options.l, options.n);
|
||||
auto b_coord = cutlass::make_Coord(options.k, options.n * options.l);
|
||||
auto groupscale_a_coord = cutlass::make_Coord(groupscale_m * options.l, blockscale_k);
|
||||
auto blockscale_b_coord = cutlass::make_Coord(blockscale_k, blockscale_n * options.l);
|
||||
auto groupscale_b_coord = cutlass::make_Coord(groupscale_n * options.l, blockscale_k);
|
||||
|
||||
tensor_A.resize(a_coord);
|
||||
blockscale_tensor_A.resize(groupscale_a_coord);
|
||||
tensor_B.resize(b_coord);
|
||||
blockscale_tensor_B.resize(blockscale_b_coord);
|
||||
blockscale_tensor_A.resize(groupscale_a_coord);
|
||||
blockscale_tensor_B.resize(groupscale_b_coord);
|
||||
tensor_C.resize(c_coord);
|
||||
tensor_D.resize(c_coord);
|
||||
tensor_ref_D.resize(c_coord);
|
||||
@@ -393,7 +441,7 @@ void initialize(const Options<RasterOrderOptions> &options) {
|
||||
#if 0 // Dump blockscaled tensors
|
||||
std::cout << "blockscale_tensor_A: " << groupscale_a_coord << std::endl;
|
||||
std::cout << blockscale_tensor_A.host_view() << "\n";
|
||||
std::cout << "blockscale_tensor_B: " << blockscale_b_coord << std::endl;
|
||||
std::cout << "blockscale_tensor_B: " << groupscale_b_coord << std::endl;
|
||||
std::cout << blockscale_tensor_B.host_view() << "\n";
|
||||
#endif
|
||||
|
||||
@@ -441,21 +489,26 @@ void initialize(const Options<RasterOrderOptions> &options) {
|
||||
|
||||
if (IsDFp8 && options.save_amax) {
|
||||
abs_max_D.resize(cutlass::make_Coord(1));
|
||||
initialize_tensor(abs_max_D.host_view(), cutlass::Distribution::AllZeros, 0);
|
||||
abs_max_D.sync_device();
|
||||
reference_abs_max_D.resize(cutlass::make_Coord(1));
|
||||
initialize_tensor(reference_abs_max_D.host_view(), cutlass::Distribution::AllZeros, 0);
|
||||
}
|
||||
|
||||
if (IsAuxFp8 && options.save_aux && options.save_amax) {
|
||||
abs_max_aux.resize(cutlass::make_Coord(1));
|
||||
initialize_tensor(abs_max_aux.host_view(), cutlass::Distribution::AllZeros, 0);
|
||||
abs_max_aux.sync_device();
|
||||
reference_abs_max_aux.resize(cutlass::make_Coord(1));
|
||||
initialize_tensor(reference_abs_max_aux.host_view(), cutlass::Distribution::AllZeros, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// Populates a Gemm::Arguments structure from the given commandline options
|
||||
typename Gemm::Arguments args_from_options(const Options<RasterOrderOptions> &options)
|
||||
template<typename GemmArguments>
|
||||
GemmArguments args_from_options(const Options<RasterOrderOptions> &options)
|
||||
{
|
||||
typename Gemm::Arguments arguments{
|
||||
GemmArguments arguments{
|
||||
cutlass::gemm::GemmUniversalMode::kGemm,
|
||||
{options.m, options.n, options.k, options.l},
|
||||
{tensor_A.device_data(),
|
||||
@@ -513,14 +566,15 @@ typename Gemm::Arguments args_from_options(const Options<RasterOrderOptions> &op
|
||||
return arguments;
|
||||
}
|
||||
|
||||
bool verify(const Options<RasterOrderOptions> &options) {
|
||||
/// Don't know why the compiler does not like verify() being templated...
|
||||
bool verify(const Options<RasterOrderOptions> &options, const int ScaleMsPerTile, const int ScaleNsPerTile) {
|
||||
//
|
||||
// Compute reference output
|
||||
//
|
||||
|
||||
// Group scaling tensors shapes based `ScaleGranularityM`, CTA Block (TileShape) and GEMM Problem shape
|
||||
auto gemm_problem_shape = cute::make_shape(options.m, options.n, options.k);
|
||||
auto blockscale_shape = shape(get<1>(cute::zipped_divide(cute::make_layout(gemm_problem_shape), TileShape{})));
|
||||
auto blockscale_shape = shape(get<1>(cute::zipped_divide(cute::make_layout(gemm_problem_shape), TileShape_{})));
|
||||
auto blockscale_m = cute::get<0>(blockscale_shape);
|
||||
auto blockscale_n = cute::get<1>(blockscale_shape);
|
||||
auto blockscale_k = cute::get<2>(blockscale_shape);
|
||||
@@ -565,8 +619,8 @@ bool verify(const Options<RasterOrderOptions> &options) {
|
||||
);
|
||||
auto blockscale_B = cute::make_tensor(blockscale_tensor_B.host_data(),
|
||||
cute::make_layout(
|
||||
cute::make_shape(blockscale_n, blockscale_k, options.l),
|
||||
cute::make_stride(blockscale_k, 1, blockscale_n * blockscale_k)
|
||||
cute::make_shape(blockscale_n, ScaleNsPerTile, blockscale_k, options.l),
|
||||
cute::make_stride(blockscale_k * ScaleNsPerTile, 1, ScaleNsPerTile, blockscale_n * blockscale_k * ScaleNsPerTile)
|
||||
)
|
||||
);
|
||||
|
||||
@@ -575,7 +629,7 @@ bool verify(const Options<RasterOrderOptions> &options) {
|
||||
cutlass::reference::host::GettMainloopParams<ElementAccumulator,
|
||||
decltype(A), decltype(B),
|
||||
decltype(blockscale_A), decltype(blockscale_B),
|
||||
TileShape> mainloop_params{
|
||||
TileShape_> mainloop_params{
|
||||
A, B, // Operand Tensors
|
||||
blockscale_A, blockscale_B // Groupwise scaling Tensors
|
||||
};
|
||||
@@ -641,16 +695,22 @@ bool verify(const Options<RasterOrderOptions> &options) {
|
||||
}
|
||||
|
||||
/// Execute a given example GEMM computation
|
||||
template <typename Gemm>
|
||||
template <typename GroupScaleConfig, typename Gemm>
|
||||
int run(Options<RasterOrderOptions> &options)
|
||||
{
|
||||
initialize(options);
|
||||
using TileShape = typename GroupScaleConfig::TileShape;
|
||||
const int ScaleGranularityM = GroupScaleConfig::ScaleGranularityM;
|
||||
const int ScaleGranularityN = GroupScaleConfig::ScaleGranularityN;
|
||||
const int ScaleMsPerTile = GroupScaleConfig::ScaleMsPerTile;
|
||||
const int ScaleNsPerTile = GroupScaleConfig::ScaleNsPerTile;
|
||||
|
||||
initialize<GroupScaleConfig>(options);
|
||||
|
||||
// Instantiate CUTLASS kernel depending on templates
|
||||
Gemm gemm;
|
||||
|
||||
// Create a structure of gemm kernel arguments suitable for invoking an instance of Gemm
|
||||
auto arguments = args_from_options(options);
|
||||
auto arguments = args_from_options<typename Gemm::Arguments>(options);
|
||||
|
||||
// Using the arguments, query for extra workspace required for matrix multiplication computation
|
||||
size_t workspace_size = Gemm::get_workspace_size(arguments);
|
||||
@@ -669,7 +729,7 @@ int run(Options<RasterOrderOptions> &options)
|
||||
|
||||
// Check if output from CUTLASS kernel and reference kernel are equal or not
|
||||
Result result;
|
||||
result.passed = verify(options);
|
||||
result.passed = verify(options, ScaleMsPerTile, ScaleNsPerTile);
|
||||
|
||||
std::cout << " Disposition: " << (result.passed ? "Passed" : "Failed") << std::endl;
|
||||
|
||||
@@ -683,6 +743,7 @@ int run(Options<RasterOrderOptions> &options)
|
||||
GpuTimer timer;
|
||||
timer.start();
|
||||
for (int iter = 0; iter < options.iterations; ++iter) {
|
||||
CUTLASS_CHECK(gemm.initialize(arguments, workspace.get()));
|
||||
CUTLASS_CHECK(gemm.run());
|
||||
}
|
||||
timer.stop();
|
||||
@@ -702,9 +763,13 @@ int run(Options<RasterOrderOptions> &options)
|
||||
}
|
||||
|
||||
std::cout << " Problem Size: " << options.m << 'x' << options.n << 'x' << options.k << 'x' << options.l << std::endl;
|
||||
std::cout << " Tile shape (M, N, K): " << size<0>(TileShape{}) << ", " << size<1>(TileShape{}) << ", " << size<2>(TileShape{}) << std::endl;
|
||||
std::cout << " ScaleGranularityM: " << ScaleGranularityM << " (ScaleMsPerTile: " << ScaleMsPerTile << ")" << std::endl;
|
||||
std::cout << " ScaleGranularityN: " << ScaleGranularityN << " (ScaleNsPerTile: " << ScaleNsPerTile << ")" << std::endl;
|
||||
std::cout << " Rasterization: " << raster << " with a maximum CTA swizzle of " << options.swizzle << std::endl;
|
||||
std::cout << " Avg runtime: " << result.avg_runtime_ms << " ms" << std::endl;
|
||||
std::cout << " GFLOPS: " << result.gflops << std::endl;
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -753,7 +818,27 @@ int main(int argc, char const **args) {
|
||||
//
|
||||
|
||||
#if defined(CUTLASS_ARCH_MMA_SM90_SUPPORTED)
|
||||
run<Gemm>(options);
|
||||
std::cout << "Basic split-K GEMM kernel" << std::endl;
|
||||
run<GroupScale1D1DConfig, GroupScale1D1DGemm::GemmDefault>(options);
|
||||
std::cout << std::endl;
|
||||
run<GroupScale1D2DConfig, GroupScale1D2DGemm::GemmDefault>(options);
|
||||
std::cout << std::endl;
|
||||
run<GroupScale2D1DConfig, GroupScale2D1DGemm::GemmDefault>(options);
|
||||
std::cout << std::endl;
|
||||
run<GroupScale2D2DConfig, GroupScale2D2DGemm::GemmDefault>(options);
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
std::cout << "StreamK GEMM kernel" << std::endl;
|
||||
run<GroupScale1D1DConfig, GroupScale1D1DGemm::GemmStreamK>(options);
|
||||
std::cout << std::endl;
|
||||
run<GroupScale1D2DConfig, GroupScale1D2DGemm::GemmStreamK>(options);
|
||||
std::cout << std::endl;
|
||||
run<GroupScale2D1DConfig, GroupScale2D1DGemm::GemmStreamK>(options);
|
||||
std::cout << std::endl;
|
||||
run<GroupScale2D2DConfig, GroupScale2D2DGemm::GemmStreamK>(options);
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -220,10 +220,12 @@ void gett_mainloop(
|
||||
int64_t block_m = m / kBlockM;
|
||||
int64_t block_n = n / kBlockN;
|
||||
cute::Tensor blockscale_A = mainloop_params.ScaleA(block_m, _, _, l);
|
||||
cute::Tensor blockscale_B = mainloop_params.ScaleB(block_n, _, l);
|
||||
cute::Tensor blockscale_B = mainloop_params.ScaleB(block_n, _, _, l);
|
||||
|
||||
const int ScaleGranularityM = cute::size<0>(typename MainloopParams::TileShape{}) / cute::size<1>(mainloop_params.ScaleA.shape());
|
||||
assert(cute::size<0>(typename MainloopParams::TileShape{}) == ScaleGranularityM * cute::size<1>(mainloop_params.ScaleA.shape()));
|
||||
const int ScaleGranularityN = cute::size<1>(typename MainloopParams::TileShape{}) / cute::size<1>(mainloop_params.ScaleB.shape());
|
||||
assert(cute::size<0>(typename MainloopParams::TileShape{}) == ScaleGranularityM * cute::size<1>(mainloop_params.ScaleA.shape()));
|
||||
assert(cute::size<1>(typename MainloopParams::TileShape{}) == ScaleGranularityN * cute::size<1>(mainloop_params.ScaleB.shape()));
|
||||
|
||||
// Compute on this k-block
|
||||
for (int64_t k = 0; k < cute::size<1>(mainloop_params.A.layout()); ++k) {
|
||||
@@ -231,7 +233,7 @@ void gett_mainloop(
|
||||
// Load Blockwise scaling factor from blockscale Tensors for B
|
||||
int64_t block_k = k / kBlockK;
|
||||
cute::Tensor scale_a = blockscale_A(_, block_k);
|
||||
ElementBlockScaleB scale_b = blockscale_B[block_k];
|
||||
cute::Tensor scale_b = blockscale_B(_, block_k);
|
||||
|
||||
// Load A
|
||||
ElementAccumulator a_frag[kBlockM];
|
||||
@@ -268,8 +270,10 @@ void gett_mainloop(
|
||||
// (c) Update permanent (accu)
|
||||
if ((k+1) % kBlockK == 0) {
|
||||
for (int m_b = 0; m_b < kBlockM; ++m_b) {
|
||||
auto scale_a_m_b = scale_a[m_b / ScaleGranularityM];
|
||||
for (int n_b = 0; n_b < kBlockN; ++n_b) {
|
||||
ElementAccumulator blockwise_scaled_accum = acc_temp[m_b][n_b] * scale_a[m_b / ScaleGranularityM] * scale_b;
|
||||
auto scale_b_n_b = scale_b[n_b / ScaleGranularityN];
|
||||
ElementAccumulator blockwise_scaled_accum = acc_temp[m_b][n_b] * scale_a_m_b * scale_b_n_b;
|
||||
acc[m_b][n_b] = blockwise_scaled_accum + acc[m_b][n_b];
|
||||
acc_temp[m_b][n_b] = ElementAccumulator(0);
|
||||
}
|
||||
|
||||
@@ -32,7 +32,19 @@
|
||||
|
||||
/*! \file
|
||||
\brief
|
||||
NOTE: Write docu
|
||||
Hopper Mixed-input Grouped GEMM example using CUTLASS 3 APIs for NVIDIA Hopper architecture.
|
||||
See 55_hopper_int4_bf16_gemm.cu for more details about W4A16 GEMMs with layout shuffling.
|
||||
|
||||
Limitations:
|
||||
1) Only support row-wise scaling. Zero-points and block-wise scaling is currently not supported.
|
||||
|
||||
To run this example:
|
||||
|
||||
$ ./examples/69_hopper_mixed_dtype_grouped_gemm/69_hopper_int4_bf16_grouped_gemm --m=2048 --n=2048 --k=2048 --mode=1 --groups=10
|
||||
|
||||
The above example command makes all 10 groups to be sized at the given m, n, k sizes.
|
||||
Skipping any of the problem dimensions randomizes it across the different groups.
|
||||
Same applies for alpha and beta values that are randomized across the different groups.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -32,7 +32,19 @@
|
||||
|
||||
/*! \file
|
||||
\brief
|
||||
NOTE: Write docu
|
||||
Hopper Mixed-input Grouped GEMM example using CUTLASS 3 APIs for NVIDIA Hopper architecture.
|
||||
See 55_hopper_int4_fp8_gemm.cu for more details about W4A8 GEMMs with lookup table.
|
||||
|
||||
Limitations:
|
||||
1) Only support row-wise scaling. Zero-points and block-wise scaling is currently not supported.
|
||||
|
||||
To run this example:
|
||||
|
||||
$ ./examples/69_hopper_mixed_dtype_grouped_gemm/69_hopper_int4_fp8_grouped_gemm --m=2048 --n=2048 --k=2048 --mode=1 --groups=10
|
||||
|
||||
The above example command makes all 10 groups to be sized at the given m, n, k sizes.
|
||||
Skipping any of the problem dimensions randomizes it across the different groups.
|
||||
Same applies for alpha and beta values that are randomized across the different groups.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -31,7 +31,19 @@
|
||||
|
||||
/*! \file
|
||||
\brief
|
||||
NOTE: Write docu
|
||||
Hopper Mixed-input Grouped GEMM example using CUTLASS 3 APIs for NVIDIA Hopper architecture.
|
||||
See 55_hopper_mixed_dtype_gemm.cu for more details about Mixed-input GEMMs.
|
||||
|
||||
Limitations:
|
||||
1) Only support row-wise scaling. Zero-points and block-wise scaling is currently not supported.
|
||||
|
||||
To run this example:
|
||||
|
||||
$ ./examples/69_hopper_mixed_dtype_grouped_gemm/69_hopper_mixed_dtype_grouped_gemm --m=2048 --n=2048 --k=2048 --mode=1 --groups=10
|
||||
|
||||
The above example command makes all 10 groups to be sized at the given m, n, k sizes.
|
||||
Skipping any of the problem dimensions randomizes it across the different groups.
|
||||
Same applies for alpha and beta values that are randomized across the different groups.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
|
||||
14
examples/69_hopper_mixed_dtype_grouped_gemm/README.md
Normal file
14
examples/69_hopper_mixed_dtype_grouped_gemm/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
This example extends Example 55 to support Grouped GEMMs in CUTLASS.
|
||||
|
||||
## High level overview
|
||||
|
||||
This example shows how to perform Grouped GEMMs on Hopper when A and B have different types. In the Grouped GEMM, multiple GEMMs with potentially different problem shapes can be excetued in a batch. The interface is similar to the standard mixed-input GEMM presented in Example 55, with a few noteworthy differences:
|
||||
- inside the collective builder, replace the layout types with layout pointer types.
|
||||
- in the arguments, pass the group size, array of the problem sizes, and the array of strides for matrix A and B.
|
||||
- if scales and zero-points are included, also pass the array of their strides in the arguments.
|
||||
|
||||
Note that in Example 55, the argument `--g` is used to determine the block scale size. It is important not to confuse this with the `--groups` argument in this example, which specifies the number of GEMMs.
|
||||
|
||||
## Upcoming features
|
||||
|
||||
Currently, the Mixed-input Grouped GEMM only supports row-wise scaling. Please contact us if zero-points or block-wise scaling are needed.
|
||||
@@ -115,15 +115,11 @@ using OperatorClass = cutlass::arch::OpClassTensorOp; // O
|
||||
using MmaTileShape_MNK = Shape<_256,_128,_64>;
|
||||
// Shape of the threadblocks in a cluster
|
||||
using ClusterShape_MNK = Shape<_2,_2,_1>;
|
||||
// Shape of the threadblocks participating in a tcgen05 MMA. <1, 1, 1> for cta_group = 1, <2, 1, 1> for cta_group = 2
|
||||
using AtomThrShape_MNK = Shape<_2, _1, _1>;
|
||||
// Shape of the tile computed by each SM
|
||||
using PerSmTileShape_MNK = decltype(shape_div(MmaTileShape_MNK{}, AtomThrShape_MNK{}));
|
||||
|
||||
// Build the epilogue
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
PerSmTileShape_MNK, ClusterShape_MNK,
|
||||
MmaTileShape_MNK, ClusterShape_MNK,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
|
||||
@@ -131,17 +131,13 @@ using ElementAmax = float;
|
||||
using MmaTileShape_MNK = Shape<_256,_128,_64>;
|
||||
// Shape of the threadblocks in a cluster
|
||||
using ClusterShape_MNK = Shape<_2,_2,_1>;
|
||||
// Shape of the threadblocks participating in a tcgen05 MMA. <1, 1, 1> for cta_group = 1, <2, 1, 1> for cta_group = 2
|
||||
using AtomThrShape_MNK = Shape<_2, _1, _1>;
|
||||
// Shape of the tile computed by each SM
|
||||
using PerSmTileShape_MNK = decltype(shape_div(MmaTileShape_MNK{}, AtomThrShape_MNK{}));
|
||||
|
||||
using FusionOp = cutlass::epilogue::fusion::ScaledLinCombPerRowBiasEltActAmaxAux<
|
||||
LayoutC, cutlass::epilogue::thread::ReLU, ElementD, ElementCompute, ElementAux, ElementAmax, ElementBias>;
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
cutlass::arch::Sm100, cutlass::arch::OpClassTensorOp,
|
||||
PerSmTileShape_MNK, ClusterShape_MNK,
|
||||
MmaTileShape_MNK, ClusterShape_MNK,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementCompute,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
70_blackwell_fp16_gemm
|
||||
70_blackwell_fp16_gemm.cu
|
||||
|
||||
@@ -184,12 +184,8 @@ struct ExampleRunner {
|
||||
std::is_same_v<MainloopScheduleType, cutlass::gemm::KernelTmaWarpSpecialized2SmSm100> ||
|
||||
// Auto schedule will try to select 2sm cluster MMA based on cluster M
|
||||
std::is_same_v<MainloopScheduleType, cutlass::gemm::collective::KernelScheduleAuto> && size<0>(ClusterShapeMNK{}) % 2 == 0;
|
||||
// The MNK layout of CTAs within a cluster MMA
|
||||
using AtomThrMNK = std::conditional_t<Use2SmMma, Shape<_2,_1,_1>, Shape<_1,_1,_1>>;
|
||||
// The MMA tile used by the mainloop collective. Blackwell 1sm MMA supports up to MMA tile M = 128, 2sm MMA supports up to MMA tile M = 256
|
||||
using MmaTileMNK = std::conditional_t<Use2SmMma, Shape<_256,_128,_64>, Shape<_128,_128,_64>>;
|
||||
// The Output tile used by the epilogue collective
|
||||
using OutputTileMNK = decltype(shape_div(MmaTileMNK{}, AtomThrMNK{}));
|
||||
|
||||
// 16B alignment lets us use TMA
|
||||
static constexpr int AlignmentA = 128 / cutlass::sizeof_bits<ElementA>::value;
|
||||
@@ -220,7 +216,7 @@ struct ExampleRunner {
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
cutlass::arch::Sm100, cutlass::arch::OpClassTensorOp,
|
||||
OutputTileMNK, ClusterShapeMNK,
|
||||
MmaTileMNK, ClusterShapeMNK,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementCompute,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
@@ -503,20 +499,20 @@ if (__CUDACC_VER_MAJOR__ < 12 || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MIN
|
||||
print_result("KernelScheduleAuto mainloop schedule with EpilogueScheduleAuto epilogue schedule and 3 mainloop stages", passed);
|
||||
|
||||
// 1SM cluster MMA mainloop schedules can be used with direct store ("no-smem") epilogue schedules
|
||||
ExampleRunner<cutlass::gemm::KernelTmaWarpSpecialized1SmSm100, cutlass::epilogue::NoSmemWarpSpecialized> runner_2;
|
||||
ExampleRunner<cutlass::gemm::KernelTmaWarpSpecialized1SmSm100, cutlass::epilogue::NoSmemWarpSpecialized1Sm> runner_2;
|
||||
passed = runner_2.run(options, hw_info);
|
||||
print_result("KernelTmaWarpSpecialized1SmSm100 mainloop schedule with NoSmemWarpSpecialized epilogue schedule", passed);
|
||||
print_result("KernelTmaWarpSpecialized1SmSm100 mainloop schedule with NoSmemWarpSpecialized1Sm epilogue schedule", passed);
|
||||
|
||||
// 1SM cluster MMA mainloop schedules can also be used with 1SM TMA epilogue schedules
|
||||
// 1SM cluster MMA mainloop schedules will not work with 2SM TMA epilogue schedules
|
||||
ExampleRunner<cutlass::gemm::KernelTmaWarpSpecialized1SmSm100, cutlass::epilogue::TmaWarpSpecialized1Sm> runner_3;
|
||||
passed = runner_3.run(options, hw_info);
|
||||
print_result("KernelTmaWarpSpecialized1SmSm100 mainloop schedule with NoSmemWarpSpecialized epilogue schedule", passed);
|
||||
print_result("KernelTmaWarpSpecialized1SmSm100 mainloop schedule with TmaWarpSpecialized1Sm epilogue schedule", passed);
|
||||
|
||||
// 2SM cluster MMA mainloop schedules can be used with direct store ("no-smem") epilogue schedules
|
||||
ExampleRunner<cutlass::gemm::KernelTmaWarpSpecialized2SmSm100, cutlass::epilogue::NoSmemWarpSpecialized> runner_4;
|
||||
ExampleRunner<cutlass::gemm::KernelTmaWarpSpecialized2SmSm100, cutlass::epilogue::NoSmemWarpSpecialized2Sm> runner_4;
|
||||
passed = runner_4.run(options, hw_info);
|
||||
print_result("KernelTmaWarpSpecialized2SmSm100 mainloop schedule with NoSmemWarpSpecialized epilogue schedule", passed);
|
||||
print_result("KernelTmaWarpSpecialized2SmSm100 mainloop schedule with NoSmemWarpSpecialized2Sm epilogue schedule", passed);
|
||||
|
||||
// 2SM cluster MMA mainloop schedules can also be used with 2SM TMA epilogue schedules
|
||||
// 2SM cluster MMA mainloop schedules will not work with SM TMA epilogue schedules
|
||||
@@ -556,11 +552,11 @@ if (__CUDACC_VER_MAJOR__ < 12 || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MIN
|
||||
// Blackwell direct store epilogue schedule supports custom EVTs and named fusion operations as well (not supported for pre-Blackwell kernels)
|
||||
ExampleRunner<
|
||||
cutlass::gemm::KernelTmaWarpSpecialized1SmSm100,
|
||||
cutlass::epilogue::NoSmemWarpSpecialized,
|
||||
cutlass::epilogue::NoSmemWarpSpecialized1Sm,
|
||||
cutlass::gemm::collective::StageCountAuto,
|
||||
UseCustomEVT> runner_9;
|
||||
passed = runner_9.run(options, hw_info);
|
||||
print_result("KernelTmaWarpSpecialized1SmSm100 mainloop schedule with NoSmemWarpSpecialized epilogue and custom EVT", passed);
|
||||
print_result("KernelTmaWarpSpecialized1SmSm100 mainloop schedule with NoSmemWarpSpecialized1Sm epilogue and custom EVT", passed);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
# Both filenames are shorter to avoid MAX_PATH issues on Windows.
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
71_blackwell_gemm_with_collective_builder
|
||||
71_blackwell_gemm_with_collective_builder.cu
|
||||
|
||||
@@ -117,11 +117,10 @@ using OperatorClass = cutlass::arch::OpClassBlockScaledTensorOp; // O
|
||||
// Kernel Perf config
|
||||
using MmaTileShape = Shape<_256,_256,_256>; // MMA's tile size
|
||||
using ClusterShape = Shape<_4,_4,_1>; // Shape of the threadblocks in a cluster
|
||||
using PerSmTileShape_MNK = Shape<_128,_256,_256>; // Threadblock-level tile size
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
PerSmTileShape_MNK, ClusterShape,
|
||||
MmaTileShape, ClusterShape,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutCTag, AlignmentC,
|
||||
|
||||
@@ -121,7 +121,6 @@ using OperatorClass = cutlass::arch::OpClassBlockScaledTensorOp; // O
|
||||
// Kernel Perf config
|
||||
using MmaTileShape = Shape<_128,_128,_256>; // MMA's tile size
|
||||
using ClusterShape = Shape<_1,_1,_1>; // Shape of the threadblocks in a cluster
|
||||
using PerSmTileShape_MNK = Shape<_128,_128,_256>; // Threadblock-level tile size
|
||||
|
||||
constexpr int InputSFVectorSize = 16;
|
||||
constexpr int OutputSFVectorSize = InputSFVectorSize;
|
||||
@@ -137,7 +136,7 @@ using FusionOperation = cutlass::epilogue::fusion::LinCombBlockScaleFactor<
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
PerSmTileShape_MNK, ClusterShape,
|
||||
MmaTileShape, ClusterShape,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutCTag, AlignmentC,
|
||||
|
||||
@@ -118,11 +118,10 @@ using OperatorClass = cutlass::arch::OpClassBlockScaledTensorOp; // O
|
||||
// Kernel Perf config
|
||||
using MmaTileShape = Shape<_256,_256,_256>; // MMA's tile size
|
||||
using ClusterShape = Shape<_4,_4,_1>; // Shape of the threadblocks in a cluster
|
||||
using PerSmTileShape_MNK = Shape<_128,_256,_256>; // Threadblock-level tile size
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
PerSmTileShape_MNK, ClusterShape,
|
||||
MmaTileShape, ClusterShape,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutCTag, AlignmentC,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
72a_blackwell_nvfp4_bf16_gemm
|
||||
72a_blackwell_nvfp4_bf16_gemm.cu
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
|
||||
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
73_blackwell_gemm_preferred_cluster
|
||||
blackwell_gemm_preferred_cluster.cu
|
||||
|
||||
@@ -129,27 +129,22 @@ using OperatorClass = cutlass::arch::OpClassTensorOp; // O
|
||||
// MMA and Cluster Tile Shapes
|
||||
// Shape of the tile computed by tcgen05 MMA, could be across 2 SMs if Cluster Shape % 2 == 0
|
||||
using MmaTileShape_MNK = Shape<_256,_128,_64>;
|
||||
// Shape of the threadblocks participating in a tcgen05 MMA. <1, 1, 1> for cta_group = 1, <2, 1, 1> for cta_group = 2
|
||||
using AtomThrShape_MNK = Shape<_2, _1, _1>;
|
||||
// Shape of the tile computed by each SM
|
||||
using PerSmTileShape_MNK = decltype(shape_div(MmaTileShape_MNK{}, AtomThrShape_MNK{}));
|
||||
// Shape of the cluster set to <int,int,_1> to indicate dynamic cluster shape
|
||||
using ClusterShape_MNK = Shape<int,int,_1>;
|
||||
// When dynamic cluster is used, KernelScheduleAuto always selects mainloop dispatch policy that
|
||||
// lowers to tcgen05 MMA cta_group = 1 as we don't know if the dynamic cluster M dimension will be a multiple of 2
|
||||
// To use KernelScheduleAuto, users need to set AtomThrShape_MNK to Shape<1, 1, 1>
|
||||
using KernelSchedule = cute::conditional_t<cute::size(AtomThrShape_MNK{}) == 2,
|
||||
cutlass::gemm::KernelTmaWarpSpecialized2SmSm100,
|
||||
cutlass::gemm::collective::KernelScheduleAuto>;
|
||||
// To use tcgen05 MMA cta_group = 2, users must explicitly use 2sm builder schedules
|
||||
using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecialized2SmSm100;
|
||||
using EpilogueSchedule = cutlass::epilogue::TmaWarpSpecialized2Sm;
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
PerSmTileShape_MNK, ClusterShape_MNK,
|
||||
MmaTileShape_MNK, ClusterShape_MNK,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
cutlass::epilogue::collective::EpilogueScheduleAuto
|
||||
EpilogueSchedule
|
||||
>::CollectiveOp;
|
||||
|
||||
using CollectiveMainloop = typename cutlass::gemm::collective::CollectiveBuilder<
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
|
||||
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
74_blackwell_gemm_streamk
|
||||
blackwell_gemm_streamk.cu
|
||||
|
||||
@@ -133,22 +133,17 @@ using OperatorClass = cutlass::arch::OpClassTensorOp; // O
|
||||
// MMA and Cluster Tile Shapes
|
||||
// Shape of the tile computed by tcgen05 MMA, could be across 2 SMs if Cluster Shape % 2 == 0
|
||||
using MmaTileShape_MNK = Shape<_256,_128,_64>;
|
||||
// Shape of the threadblocks participating in a tcgen05 MMA. <1, 1, 1> for cta_group = 1, <2, 1, 1> for cta_group = 2
|
||||
using AtomThrShape_MNK = Shape<_2, _1, _1>;
|
||||
// Shape of the tile computed by each SM
|
||||
using PerSmTileShape_MNK = decltype(shape_div(MmaTileShape_MNK{}, AtomThrShape_MNK{}));
|
||||
// Shape of the cluster set to <int,int,_1> to indicate dynamic cluster shape
|
||||
using ClusterShape_MNK = Shape<int,int,_1>;
|
||||
// When dynamic cluster is used, KernelScheduleAuto always selects mainloop dispatch policy that
|
||||
// When dynamic cluster is used, KernelScheduleAuto always selects mainloop dispatch policy that
|
||||
// lowers to tcgen05 MMA cta_group = 1 as we don't know if the dynamic cluster M dimension will be a multiple of 2
|
||||
// To use KernelScheduleAuto, users need to set AtomThrShape_MNK to Shape<1, 1, 1>
|
||||
using KernelSchedule = cute::conditional_t<cute::size(AtomThrShape_MNK{}) == 2,
|
||||
cutlass::gemm::KernelTmaWarpSpecialized2SmSm100,
|
||||
cutlass::gemm::collective::KernelScheduleAuto>;
|
||||
// To use tcgen05 MMA cta_group = 2, users must explicitly use 2sm builder schedules
|
||||
using KernelSchedule = cutlass::gemm::KernelTmaWarpSpecialized2SmSm100;
|
||||
using EpilogueSchedule = cutlass::epilogue::TmaWarpSpecialized2Sm;
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
PerSmTileShape_MNK, ClusterShape_MNK,
|
||||
MmaTileShape_MNK, ClusterShape_MNK,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
|
||||
@@ -121,32 +121,25 @@ using StageCountType = cutlass::gemm::collective::StageCountAuto; // S
|
||||
|
||||
// Runtime Cluster Shape
|
||||
using ClusterShape = Shape<int32_t,int32_t,_1>;
|
||||
// For Static Cluster Shape:
|
||||
// using ClusterShape = Shape<_2,_1,_1>; // for example
|
||||
// using AtomThrShape = decltype(shape_div(ClusterShape{}, Shape<_2,_1,_1>{})); // for 2SM config
|
||||
// using OutputTileShape = decltype(shape_div(ClusterTileShape{}, ClusterShape{})); // for epilogue builder
|
||||
// using MmaTileShape = decltype(shape_div(ClusterTileShape{}, AtomThrShape{})); // for mainloop builder
|
||||
|
||||
// Different configs for 1SM and 2SM MMA kernel
|
||||
struct MMA1SMConfig {
|
||||
using MmaTileShape = Shape<_128,_256,Int<128 / sizeof(ElementA)>>;
|
||||
using KernelSchedule = cutlass::gemm::KernelPtrArrayTmaWarpSpecialized1SmSm100; // Kernel to launch
|
||||
using EpilogueSchedule = cutlass::epilogue::PtrArrayTmaWarpSpecialized1Sm; // Epilogue to launch
|
||||
using OutputTileShape = decltype(shape_div(MmaTileShape{}, Shape<_1,_1,_1>{}));
|
||||
};
|
||||
|
||||
struct MMA2SMConfig {
|
||||
using MmaTileShape = Shape<_256,_256,Int<128 / sizeof(ElementA)>>;
|
||||
using KernelSchedule = cutlass::gemm::KernelPtrArrayTmaWarpSpecialized2SmSm100; // Kernel to launch
|
||||
using EpilogueSchedule = cutlass::epilogue::PtrArrayTmaWarpSpecialized2Sm; // Epilogue to launch
|
||||
using OutputTileShape = decltype(shape_div(MmaTileShape{}, Shape<_2,_1,_1>{}));
|
||||
};
|
||||
|
||||
template <typename ScheduleConfig>
|
||||
struct GivenGemmSchedule {
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
typename ScheduleConfig::OutputTileShape, ClusterShape,
|
||||
typename ScheduleConfig::MmaTileShape, ClusterShape,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutC *, AlignmentC,
|
||||
|
||||
@@ -143,31 +143,23 @@ using StageCountType = cutlass::gemm::collective::StageCountAuto; // S
|
||||
|
||||
// Runtime Cluster Shape
|
||||
using ClusterShape = Shape<int32_t,int32_t,_1>;
|
||||
/* // For Static Cluster Shape:
|
||||
use ClusterShape = Shape<_2,_1,_1> for example
|
||||
using AtomThrShape = decltype(shape_div(ClusterShape{}, Shape<_2,_1,_1>{})); // for 2SM config
|
||||
using OutputTileShape = decltype(shape_div(ClusterTileShape{}, ClusterShape{})); // for epilogue builder
|
||||
using MmaTileShape = decltype(shape_div(ClusterTileShape{}, AtomThrShape{})); // for mainloop builder
|
||||
*/
|
||||
|
||||
// Different configs for 1SM and 2SM MMA kernel
|
||||
struct MMA1SMConfig {
|
||||
using MmaTileShape = Shape<_128,_256,_256>;
|
||||
using KernelSchedule = cutlass::gemm::KernelPtrArrayTmaWarpSpecialized1SmNvf4Sm100; // Kernel to launch
|
||||
using EpilogueSchedule = cutlass::epilogue::PtrArrayTmaWarpSpecialized1Sm; // Epilogue to launch
|
||||
using OutputTileShape = decltype(shape_div(MmaTileShape{}, Shape<_1,_1,_1>{}));
|
||||
};
|
||||
|
||||
struct MMA2SMConfig {
|
||||
using MmaTileShape = Shape<_256,_256,_256>;
|
||||
using KernelSchedule = cutlass::gemm::KernelPtrArrayTmaWarpSpecialized2SmNvf4Sm100; // Kernel to launch
|
||||
using EpilogueSchedule = cutlass::epilogue::PtrArrayTmaWarpSpecialized2Sm; // Epilogue to launch
|
||||
using OutputTileShape = decltype(shape_div(MmaTileShape{}, Shape<_2,_1,_1>{}));
|
||||
};
|
||||
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, EpilogueOperatorClass,
|
||||
typename MMA1SMConfig::OutputTileShape, ClusterShape,
|
||||
typename MMA1SMConfig::MmaTileShape, ClusterShape,
|
||||
Shape<_128,_64>,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutC *, AlignmentC,
|
||||
@@ -195,7 +187,7 @@ using Gemm = Gemm1SM;
|
||||
|
||||
using CollectiveEpilogue2SM = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, EpilogueOperatorClass,
|
||||
typename MMA2SMConfig::OutputTileShape, ClusterShape,
|
||||
typename MMA2SMConfig::MmaTileShape, ClusterShape,
|
||||
Shape<_128,_64>,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutC *, AlignmentC,
|
||||
|
||||
@@ -49,7 +49,7 @@ set(TEST_SMALL_LARGE_GROUP --m=128 --n=128 --groups=50 --iterations=0)
|
||||
set(TEST_RANDOM_PERF --iterations=10) # Random problem sizes
|
||||
set(TEST_RANDOM_PERF_LARGE_GROUP --groups=50 --iterations=10) # Random problem sizes
|
||||
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
75_blackwell_grouped_gemm
|
||||
75_blackwell_grouped_gemm.cu
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
|
||||
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
76_blackwell_conv_fprop
|
||||
76_blackwell_conv_fprop.cu
|
||||
|
||||
@@ -49,7 +49,7 @@ set(TEST_GEN_REMAP --b=2 --h=4 --h_k=2 --k=512 --d=128 --verify --remap)
|
||||
set(TEST_GEN_CACHEONLY --b=2 --h=4 --h_k=2 --k=512 --d=128 --verify --cache-only)
|
||||
|
||||
if(NOT WIN32 AND (NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")))
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
77_blackwell_fmha_fp8
|
||||
77_blackwell_fmha.cu
|
||||
|
||||
@@ -106,25 +106,23 @@ using ArchTag = cutlass::arch::Sm100; // T
|
||||
using OperatorClass = cutlass::arch::OpClassTensorOp; // Operator class tag
|
||||
|
||||
// Kernel Perf config
|
||||
using ClusterTileShape = Shape<_256,_128,_16>; // Cluster-level tile shape
|
||||
using ClusterShape = Shape<_2,_1,_1>; // Shape of the threadblocks in a cluster
|
||||
using CtaTileShape = decltype(shape_div(ClusterTileShape{}, ClusterShape{})); // Threadblock-level tile shape
|
||||
using MmaTileShape = Shape<_256,_128,_16>; // Mma instruction shape
|
||||
using ClusterShape = Shape<_2,_1,_1>; // Shape of the threadblocks in a cluster
|
||||
using MmaTileShape = Shape<_256,_128,_16>; // Mma instruction shape
|
||||
|
||||
// Build the epilogue
|
||||
using CollectiveEpilogue = typename cutlass::epilogue::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
CtaTileShape, ClusterShape,
|
||||
MmaTileShape, ClusterShape,
|
||||
cutlass::epilogue::collective::EpilogueTileAuto,
|
||||
ElementAccumulator, ElementAccumulator,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
ElementC, LayoutC, AlignmentC,
|
||||
cutlass::epilogue::NoSmemWarpSpecialized
|
||||
cutlass::epilogue::NoSmemWarpSpecialized2Sm
|
||||
>::CollectiveOp;
|
||||
|
||||
// Build the mainloop
|
||||
// Note: Emulated BF16x9 kernels need to manually specify a mainloop schedule and cannot use KernelScheduleAuto
|
||||
using MainloopSchedule = cutlass::gemm::KernelTmaWarpSpecializedFastFP32SmemSm100;
|
||||
using MainloopSchedule = cutlass::gemm::KernelTmaWarpSpecialized2SmFastFP32SmemSm100;
|
||||
using CollectiveMainloop = typename cutlass::gemm::collective::CollectiveBuilder<
|
||||
ArchTag, OperatorClass,
|
||||
ElementA, LayoutA, AlignmentA,
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
if(NOT CUTLASS_NVCC_ARCHS STREQUAL "100")
|
||||
if (CUTLASS_NVCC_ARCHS MATCHES 100a)
|
||||
cutlass_example_add_executable(
|
||||
78_blackwell_emulated_bf16x9_gemm
|
||||
78_blackwell_emulated_bf16x9_gemm.cu
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
|
||||
Blackwell SM100 GEMM example demonstrating compatible mainloop+epilogue builder schedules and epilogue visitor tree (EVT) construction
|
||||
|
||||
* [72a_blackwell_narrow_precision_gemm](72a_blackwell_narrow_precision_gemm)
|
||||
* [72_blackwell_narrow_precision_gemm](72_blackwell_narrow_precision_gemm/)
|
||||
|
||||
Block-scaled dense GEMM example targeting the NVIDIA Blackwell SM100 Tensor Core MMA using CUTLASS 3.x APIs.
|
||||
|
||||
@@ -278,6 +278,10 @@
|
||||
|
||||
Blackwell SM100 FMHA kernel
|
||||
|
||||
* [78_blackwell_emulated_bf16x9_gemm](78_blackwell_emulated_bf16x9_gemm)
|
||||
|
||||
Blackwell SM100 FastFP32 (using BF16 to emulate SGEMM) kernel
|
||||
|
||||
# CuTe - Programming Examples
|
||||
|
||||
Examples that do not rely on CUTLASS and directly showcase the features of CuTe are located in [cutlass/examples/cute](./cute/).
|
||||
|
||||
Reference in New Issue
Block a user