@@ -58,8 +58,7 @@ void compute_ref(const ProcessingMethod processing_method,
5858 const size_t rows,
5959 const size_t cols,
6060 const size_t scales_stride_rowwise,
61- const size_t scales_stride_colwise,
62- const bool is_single_tensor)
61+ const size_t scales_stride_colwise)
6362{
6463 const size_t tile_size_Y = 32 ;
6564 const size_t tile_size_X = 32 ;
@@ -169,10 +168,8 @@ void compute_ref(const ProcessingMethod processing_method,
169168 }
170169 }
171170
172- if (is_single_tensor) {
173- for (size_t j = 0 ; j < cols; ++j) {
174- output_dbias[j] = static_cast <InputType>(output_dbias_fp32[j]);
175- }
171+ for (size_t j = 0 ; j < cols; ++j) {
172+ output_dbias[j] = static_cast <InputType>(output_dbias_fp32[j]);
176173 }
177174}
178175
@@ -250,19 +247,24 @@ void performTest(const ProcessingMethod processing_method,
250247 DType itype = TypeInfo<InputType>::dtype;
251248 DType otype = TypeInfo<OutputType>::dtype;
252249
250+ const bool compute_dbias = (processing_method == ProcessingMethod::CAST_DBIAS
251+ || processing_method == ProcessingMethod::CAST_DBIAS_DACT );
252+
253253 const size_t rows = logical_shape_vec[0 ];
254254 const size_t cols = logical_shape_vec[1 ];
255255
256256 size_t elts_num = 0 ;
257257 size_t rowwise_sfs_num = 0 ;
258258 size_t colwise_sfs_num = 0 ;
259+ size_t sum_of_last_dims = 0 ;
259260
260261 std::vector<size_t > rowwise_scales_first_dim (num_tensors, 0 );
261262 std::vector<size_t > rowwise_scales_last_dim (num_tensors, 0 );
262263 std::vector<size_t > rowwise_scales_offset (num_tensors + 1 , 0 );
263264 std::vector<size_t > colwise_scales_first_dim (num_tensors, 0 );
264265 std::vector<size_t > colwise_scales_last_dim (num_tensors, 0 );
265266 std::vector<size_t > colwise_scales_offset (num_tensors + 1 , 0 );
267+ std::vector<size_t > dbias_offsets (num_tensors + 1 , 0 );
266268
267269 for (size_t t = 0 ; t < num_tensors; ++t) {
268270 const size_t M = first_dims_h[t];
@@ -285,13 +287,13 @@ void performTest(const ProcessingMethod processing_method,
285287
286288 rowwise_sfs_num += rowwise_sfs;
287289 colwise_sfs_num += colwise_sfs;
290+ sum_of_last_dims += K;
288291
289292 rowwise_scales_offset[t+1 ] = rowwise_sfs_num;
290293 colwise_scales_offset[t+1 ] = colwise_sfs_num;
294+ dbias_offsets[t+1 ] = sum_of_last_dims;
291295 }
292296
293- const bool is_single_tensor = (shape_rep == SAME_BOTH_DIMS ) || (shape_rep == VARYING_FIRST_DIM );
294-
295297 std::vector<size_t > scales_rowwise_shape = {rowwise_sfs_num};
296298 std::vector<size_t > scales_colwise_shape = {colwise_sfs_num};
297299
@@ -311,7 +313,7 @@ void performTest(const ProcessingMethod processing_method,
311313 std::vector<fp8e8m0> out_scales_rowwise_ref (rowwise ? rowwise_sfs_num : 0 );
312314 std::vector<fp8e8m0> out_scales_colwise_ref (colwise ? colwise_sfs_num : 0 );
313315
314- std::vector<InputType> ref_output_dbias (is_single_tensor ? cols : 0 );
316+ std::vector<InputType> ref_output_dbias (sum_of_last_dims, static_cast <InputType>( 0 . 0f ) );
315317
316318 for (size_t i = 0 ; i < elts_num; ++i) {
317319 const float val = dis (gen);
@@ -336,22 +338,24 @@ void performTest(const ProcessingMethod processing_method,
336338
337339 const size_t in_data_size = elts_num * sizeof (InputType);
338340 const size_t out_data_size = elts_num * sizeof (OutputType);
341+ const size_t dbias_data_size = sum_of_last_dims * sizeof (InputType);
339342 const size_t rowwise_scales_size = rowwise_sfs_num * sizeof (fp8e8m0);
340343 const size_t colwise_scales_size = colwise_sfs_num * sizeof (fp8e8m0);
341344
342345 const size_t first_dims_size = num_tensors * sizeof (size_t );
343346 const size_t last_dims_size = num_tensors * sizeof (size_t );
344347 const size_t offsets_size = (num_tensors + 1 ) * sizeof (size_t );
345348
346- InputType* grad_data_d;
347- InputType* in_data_d;
348- OutputType* out_data_rowwise_d;
349- OutputType* out_data_colwise_d;
350- fp8e8m0* out_scales_rowwise_d;
351- fp8e8m0* out_scales_colwise_d;
352- size_t * first_dims_d;
353- size_t * last_dims_d;
354- size_t * offsets_d;
349+ InputType* grad_data_d = nullptr ;
350+ InputType* in_data_d = nullptr ;
351+ InputType* dbias_out_data_d = nullptr ;
352+ OutputType* out_data_rowwise_d = nullptr ;
353+ OutputType* out_data_colwise_d = nullptr ;
354+ fp8e8m0* out_scales_rowwise_d = nullptr ;
355+ fp8e8m0* out_scales_colwise_d = nullptr ;
356+ size_t * first_dims_d = nullptr ;
357+ size_t * last_dims_d = nullptr ;
358+ size_t * offsets_d = nullptr ;
355359
356360 cudaMalloc ((void **)&grad_data_d, in_data_size);
357361 cudaMalloc ((void **)&in_data_d, in_data_size);
@@ -367,6 +371,10 @@ void performTest(const ProcessingMethod processing_method,
367371
368372 NVTEShape logical_shape_ = nvte_make_shape (logical_shape_vec.data (), logical_shape_vec.size ());
369373
374+ std::vector<size_t > dbias_logical_shape_vec= {num_tensors, cols};
375+ NVTEShape dbias_logical_shape_ = nvte_make_shape (dbias_logical_shape_vec.data (),
376+ dbias_logical_shape_vec.size ());
377+
370378 NVTEShape first_dims_shape_;
371379 NVTEShape last_dims_shape_;
372380 NVTEShape offsets_shape_;
@@ -382,6 +390,7 @@ void performTest(const ProcessingMethod processing_method,
382390 NVTEGroupedTensor grad_group_tensor = nvte_create_grouped_tensor (NVTE_DELAYED_TENSOR_SCALING , num_tensors, logical_shape_);
383391 NVTEGroupedTensor in_group_tensor = nvte_create_grouped_tensor (NVTE_DELAYED_TENSOR_SCALING , num_tensors, logical_shape_);
384392 NVTEGroupedTensor out_group_tensor = nvte_create_grouped_tensor (NVTE_MXFP8_1D_SCALING , num_tensors, logical_shape_);
393+ NVTEGroupedTensor output_dbias_tensor = nvte_create_grouped_tensor (NVTE_DELAYED_TENSOR_SCALING , num_tensors, dbias_logical_shape_);
385394
386395 NVTEBasicTensor grad_data_tensor = {grad_data_d, static_cast <NVTEDType>(itype), logical_shape_};
387396 NVTEBasicTensor in_data_tensor = {in_data_d, static_cast <NVTEDType>(itype), logical_shape_};
@@ -453,52 +462,41 @@ void performTest(const ProcessingMethod processing_method,
453462 &out_scales_colwise_tensor, sizeof (out_scales_colwise_tensor));
454463 }
455464
456- Tensor output_dbias (" output_dbias" , std::vector<size_t >{ cols }, itype);
465+ if (compute_dbias) {
466+ cudaMalloc ((void **)&dbias_out_data_d, dbias_data_size);
467+ cudaMemset (dbias_out_data_d, 0 , dbias_data_size);
468+ NVTEBasicTensor output_dbias_data_tensor = {dbias_out_data_d, static_cast <NVTEDType>(itype), dbias_logical_shape_};
469+ nvte_set_grouped_tensor_param (output_dbias_tensor, NVTEGroupedTensorParam::kNVTEGroupedRowwiseData ,
470+ &output_dbias_data_tensor, sizeof (output_dbias_data_tensor));
471+ }
457472
458473 // Reference (CPU)
459- if (is_single_tensor) {
460-
461- const size_t unpadded_rowwise_blocks_X = divide_round_up (cols, 32 );
462- const size_t unpadded_colwise_blocks_X = cols;
474+ for (size_t t = 0 ; t < num_tensors; ++t) {
475+ const size_t M = first_dims_h[t];
476+ const size_t K = last_dims_h[t];
463477
464- const size_t scales_stride_rowwise = round_up_to_nearest_multiple (unpadded_rowwise_blocks_X, 4 );
465- const size_t scales_stride_colwise = round_up_to_nearest_multiple (unpadded_colwise_blocks_X, 128 );
478+ const size_t scales_stride_rowwise = rowwise_scales_last_dim[t];
479+ const size_t scales_stride_colwise = colwise_scales_last_dim[t];
480+ const size_t data_offset = offsets_h[t];
481+ const size_t rowwise_sfs_offset = rowwise_scales_offset[t];
482+ const size_t colwise_sfs_offset = colwise_scales_offset[t];
483+ const size_t dbias_offset = dbias_offsets[t];
484+
485+ const InputType* const grad_ptr = grad_data.data () + data_offset;
486+ const InputType* const in_ptr = in_data.data () + data_offset;
487+ OutputType* const out_data_rowwise_ptr = out_data_rowwise_ref.data () + data_offset;
488+ OutputType* const out_data_colwise_ptr = out_data_colwise_ref.data () + data_offset;
489+ fp8e8m0* const out_scales_rowwise_ptr = out_scales_rowwise_ref.data () + rowwise_sfs_offset;
490+ fp8e8m0* const out_scales_colwise_ptr = out_scales_colwise_ref.data () + colwise_sfs_offset;
491+ InputType* const ref_output_dbias_ptr = ref_output_dbias.data () + dbias_offset;
466492
467493 compute_ref<InputType, OutputType>(
468- processing_method, OP , rowwise, colwise, in_data. data (), grad_data. data () ,
469- out_data_rowwise_ref. data (), out_data_colwise_ref. data () ,
470- out_scales_rowwise_ref. data (), out_scales_colwise_ref. data () ,
471- ref_output_dbias. data (), rows, cols ,
494+ processing_method, OP , rowwise, colwise, in_ptr, grad_ptr ,
495+ out_data_rowwise_ptr, out_data_colwise_ptr ,
496+ out_scales_rowwise_ptr, out_scales_colwise_ptr ,
497+ ref_output_dbias_ptr, M, K ,
472498 scales_stride_rowwise,
473- scales_stride_colwise,
474- is_single_tensor);
475- } else {
476- for (size_t t = 0 ; t < num_tensors; ++t) {
477- const size_t M = first_dims_h[t];
478- const size_t K = last_dims_h[t];
479-
480- const size_t scales_stride_rowwise = rowwise_scales_last_dim[t];
481- const size_t scales_stride_colwise = colwise_scales_last_dim[t];
482- const size_t data_offset = offsets_h[t];
483- const size_t rowwise_sfs_offset = rowwise_scales_offset[t];
484- const size_t colwise_sfs_offset = colwise_scales_offset[t];
485-
486- const InputType* const grad_ptr = grad_data.data () + data_offset;
487- const InputType* const in_ptr = in_data.data () + data_offset;
488- OutputType* const out_data_rowwise_ptr = out_data_rowwise_ref.data () + data_offset;
489- OutputType* const out_data_colwise_ptr = out_data_colwise_ref.data () + data_offset;
490- fp8e8m0* const out_scales_rowwise_ptr = out_scales_rowwise_ref.data () + rowwise_sfs_offset;
491- fp8e8m0* const out_scales_colwise_ptr = out_scales_colwise_ref.data () + colwise_sfs_offset;
492-
493- compute_ref<InputType, OutputType>(
494- processing_method, OP , rowwise, colwise, in_ptr, grad_ptr,
495- out_data_rowwise_ptr, out_data_colwise_ptr,
496- out_scales_rowwise_ptr, out_scales_colwise_ptr,
497- ref_output_dbias.data (), M, K,
498- scales_stride_rowwise,
499- scales_stride_colwise,
500- is_single_tensor);
501- }
499+ scales_stride_colwise);
502500 }
503501
504502 // GPU
@@ -509,9 +507,9 @@ void performTest(const ProcessingMethod processing_method,
509507 break ;
510508 }
511509 case ProcessingMethod::CAST_DBIAS : {
512- nvte_group_quantize_dbias (grad_group_tensor, out_group_tensor, output_dbias. data () , workspace.data (), 0 );
510+ nvte_group_quantize_dbias (grad_group_tensor, out_group_tensor, output_dbias_tensor , workspace.data (), 0 );
513511 workspace = Tensor (" workspace" , workspace.rowwise_shape (), workspace.dtype ());
514- nvte_group_quantize_dbias (grad_group_tensor, out_group_tensor, output_dbias. data () , workspace.data (), 0 );
512+ nvte_group_quantize_dbias (grad_group_tensor, out_group_tensor, output_dbias_tensor , workspace.data (), 0 );
515513 break ;
516514 }
517515 case ProcessingMethod::CAST_DBIAS_DACT : {
@@ -522,10 +520,10 @@ void performTest(const ProcessingMethod processing_method,
522520 else if (OP == &dsrelu) { nvte_group_quantize_dbias_dact = &nvte_group_quantize_dbias_dsrelu; }
523521
524522 nvte_group_quantize_dbias_dact (grad_group_tensor, in_group_tensor, out_group_tensor,
525- output_dbias. data () , workspace.data (), 0 );
523+ output_dbias_tensor , workspace.data (), 0 );
526524 workspace = Tensor (" workspace" , workspace.rowwise_shape (), workspace.dtype ());
527525 nvte_group_quantize_dbias_dact (grad_group_tensor, in_group_tensor, out_group_tensor,
528- output_dbias. data () , workspace.data (), 0 );
526+ output_dbias_tensor , workspace.data (), 0 );
529527 break ;
530528 }
531529 case ProcessingMethod::CAST_ACT : {
@@ -586,9 +584,10 @@ void performTest(const ProcessingMethod processing_method,
586584 out_data_colwise_h.data (), rows, cols, false , mismatches_elts);
587585 }
588586
589- if (processing_method == ProcessingMethod::CAST_DBIAS
590- || processing_method == ProcessingMethod::CAST_DBIAS_DACT )
591- {
587+ if (compute_dbias) {
588+ Tensor output_dbias (" output_dbias" , std::vector<size_t >{ sum_of_last_dims }, itype);
589+ cudaMemcpy (output_dbias.rowwise_dptr (), dbias_out_data_d, dbias_data_size, cudaMemcpyDeviceToDevice);
590+
592591 auto [atol_dbias, rtol_dbias] = getTolerances (itype);
593592 if (itype == DType::kFloat32 ) {
594593 atol_dbias = 1e-4 ;
@@ -601,6 +600,7 @@ void performTest(const ProcessingMethod processing_method,
601600
602601 cudaFree (grad_data_d);
603602 cudaFree (in_data_d);
603+ cudaFree (dbias_out_data_d);
604604 cudaFree (first_dims_d);
605605 cudaFree (last_dims_d);
606606 cudaFree (offsets_d);
@@ -648,7 +648,8 @@ std::vector<std::vector<size_t>> input_config = {
648648 {SAME_BOTH_DIMS , 1 , 128 ,128 },
649649 {SAME_BOTH_DIMS , 2 , 256 ,128 },
650650 {VARYING_FIRST_DIM , 2 , 512 ,128 , 128 ,384 },
651- {VARYING_FIRST_DIM , 2 , 384 ,160 , 128 ,256 },
651+ {VARYING_FIRST_DIM , 3 , 1024 ,144 , 128 ,384 ,512 },
652+ {VARYING_FIRST_DIM , 4 , 1536 ,160 , 128 ,384 ,512 ,512 },
652653 {VARYING_FIRST_DIM , 5 , 4096 ,512 , 128 ,256 ,384 ,1024 ,2304 },
653654 {VARYING_LAST_DIM , 3 , 256 ,896 , 128 ,256 ,512 },
654655 {VARYING_BOTH_DIMS , 2 , 1 ,(128 *128 )+(256 *256 ), 128 ,256 , 128 ,256 },
@@ -714,26 +715,31 @@ TEST_P(GroupedFusedCastMXFP8TestSuite, Test) {
714715 }
715716 }
716717 offsets[t+1 ] = offsets[t] + first_dims[t] * last_dims[t];
717- // Skips tests if tensor shape is not as required by the kernel
718- if (first_dims[t] % 128 != 0 ) {
718+ // Skip tests when the tensor shape is incompatible with the kernel.
719+ // The TMA engine requires strides to be 16-byte aligned.
720+ if ((first_dims[t] % 128 != 0 ) || (last_dims[t] % 16 != 0 )) {
719721 GTEST_SKIP ();
720722 }
721- if (!is_single_tensor && (last_dims[t] % 128 != 0 )) {
723+ // If a grouped tensor has a varying last dimension, it must be a multiple of 128.
724+ // Otherwise, computing the grid size adds runtime overhead in the non-persistent kernel,
725+ // since the relevant tensor metadata resides in device memory.
726+ constexpr size_t CHUNK_DIM_X = 128 ;
727+ if (!is_single_tensor && (last_dims[t] % CHUNK_DIM_X != 0 )) {
722728 GTEST_SKIP ();
723729 }
724730 }
725- // Skips DBias tests if last dimension of tensors variates
731+ // Skip dBias tests when tensors in the group have different last dimensions.
726732 if ((processing_method == ProcessingMethod::CAST_DBIAS || processing_method == ProcessingMethod::CAST_DBIAS_DACT )
727733 && !is_single_tensor) {
728734 GTEST_SKIP ();
729735 }
730736
731- // Skips non Act tests if the Activation type is not an identity
737+ // Skip non-activation tests when the activation type is not Identity.
732738 if ((processing_method == ProcessingMethod::CAST_ONLY || processing_method == ProcessingMethod::CAST_DBIAS )
733739 && activation != ActivationKind::Identity) {
734740 GTEST_SKIP ();
735741 }
736- // Skips Act tests if the Activation is an identity
742+ // Skip activation tests when the activation type is Identity.
737743 if ((processing_method == ProcessingMethod::CAST_DBIAS_DACT
738744 || processing_method == ProcessingMethod::CAST_DACT
739745 || processing_method == ProcessingMethod::CAST_ACT ) && (activation == ActivationKind::Identity)) {
0 commit comments