[HipDNN] Layernorm bwd frontend and CPU reference#6566
Conversation
8452381 to
2497b3d
Compare
3df0f50 to
9af89c1
Compare
ca6e262 to
97be077
Compare
9af89c1 to
af9142d
Compare
df3c852 to
963e9de
Compare
5892360 to
6a69aa7
Compare
Codecov Report❌ Patch coverage is ❌ Your project status has failed because the head coverage (76.92%) is below the target coverage (80.00%). You can increase the head coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## develop #6566 +/- ##
===========================================
+ Coverage 71.33% 71.40% +0.07%
===========================================
Files 2628 2636 +8
Lines 413045 414443 +1398
Branches 61875 62073 +198
===========================================
+ Hits 294615 295905 +1290
- Misses 96656 96686 +30
- Partials 21774 21852 +78
*This pull request uses carry forward flags. Click here to find out more.
🚀 New features to boost your workflow:
|
4a09af0 to
c253cda
Compare
2c0b8c5 to
328b560
Compare
| ^ (static_cast<std::size_t>(static_cast<int>(dxDataType)) << 16) | ||
| ^ (static_cast<std::size_t>(static_cast<int>(scaleBiasDataType)) << 8) | ||
| ^ (static_cast<std::size_t>(static_cast<int>(meanInvVarianceDataType)) << 12) | ||
| ^ (static_cast<std::size_t>(static_cast<int>(outputDataType)) << 16) | ||
| ^ (static_cast<std::size_t>(static_cast<int>(computeDataType)) << 20); |
There was a problem hiding this comment.
Nit: I think here we can drop the cast to int.
There was a problem hiding this comment.
I must've copied that from the forward pass. I've removed it in both the forward and backward pass now.
bdb7495 to
8b51606
Compare
EwanC
left a comment
There was a problem hiding this comment.
Looking good, couple more minor comments
e85af0b to
519d1d2
Compare
| CHECK_TENSOR_TYPE(tensorMap, nodeAttributes->dscale_tensor_uid(), OutputDataTypeEnum); | ||
| CHECK_TENSOR_TYPE(tensorMap, nodeAttributes->dbias_tensor_uid(), OutputDataTypeEnum); |
There was a problem hiding this comment.
These type checks don't match the execution parameter types in projects/hipdnn/test_sdk/include/hipdnn_test_sdk/utilities/CpuFpReferenceLayernorm.hpp bprop.
I think they should be verified against ScaleBiasDataTypeEnum.
There was a problem hiding this comment.
Minor mistake, should be fixed now.
| utilities::CpuFpReferenceLayernorm::bprop(*shallowDyTensor, | ||
| *shallowXTensor, | ||
| *shallowScaleTensor, | ||
| *shallowDxTensor, | ||
| *shallowDscaleTensor, | ||
| *shallowDbiasTensor, | ||
| epsilon, | ||
| shallowMeanTensor.get(), | ||
| shallowInvVarianceTensor.get(), | ||
| _params.normalizedDimCount); |
There was a problem hiding this comment.
ComputeDataType template param isn't passed explicitly so it will default to float. You will need to explicitly pass the template params.
There was a problem hiding this comment.
I must've misjudged that ComputeDataType would be used by the arguments. Fixed now.
| // Mean/inv_variance type: use mean if present, otherwise default to IO type (dy type) | ||
| if(nodeAttributes->mean_tensor_uid().has_value()) | ||
| { | ||
| auto meanTensorAttr = tensorMap.at(nodeAttributes->mean_tensor_uid().value()); | ||
| meanInvVarianceDataType = meanTensorAttr->data_type(); | ||
| } | ||
| else | ||
| { | ||
| meanInvVarianceDataType = dyDataType; | ||
| } |
There was a problem hiding this comment.
Do we need to set meanInvVarianceDataType if the tensors are omitted?
There was a problem hiding this comment.
It was necessary to set meanInvVarianceDataType to dyDataType when mean and inverse variance were omitted for signature key lookup. I've tried to set it to UNSET instead and add plan builders for the omitted case, but that led to a bunch of compilation issues everywhere with void being the type, so I think this is cleaner solution for now.
There was a problem hiding this comment.
I think there are more tests to be added here to coincide with similar lowering integration files.
| // Standard LayernormBackward constants for testing get/set of valid operations. | ||
| // These represent "any valid layernormbackward" — specific values are not significant. |
There was a problem hiding this comment.
Specific values are insignificant, but we at least try to have UID uniqueness across all these constant files to avoid mixing up constants. Please check to make sure these UIDs values are unique, and if not, find a unique range.
There was a problem hiding this comment.
I've changed the UIDs to unique values.
| /** @brief Output gradient tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_DY = 3600, | ||
|
|
||
| /** @brief Input tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_X = 3601, | ||
|
|
||
| /** @brief Scale tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_SCALE = 3602, | ||
|
|
||
| /** @brief Mean tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_MEAN = 3603, | ||
|
|
||
| /** @brief Inverse variance tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_INV_VARIANCE = 3604, | ||
|
|
||
| /** @brief Epsilon tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_EPSILON = 3605, | ||
|
|
||
| /** @brief Input gradient tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_DX = 3606, | ||
|
|
||
| /** @brief Scale gradient tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_DSCALE = 3607, | ||
|
|
||
| /** @brief Bias gradient tensor for backward layernorm */ | ||
| HIPDNN_ATTR_OPERATION_LAYERNORM_BACKWARD_DBIAS = 3608, | ||
|
|
||
| /** @brief Number of normalized dimensions for backward layernorm */ | ||
| HIPDNN_ATTR_LAYERNORM_BACKWARD_NORMALIZED_DIM_COUNT = 3609, |
There was a problem hiding this comment.
These need to be _EXT per lack of descriptor API parity with cuDNN.
See:
There was a problem hiding this comment.
I've fixed it now (including the strings). I don't think some of these documents existed when I did this.
| // Infer output shape and strides if not set | ||
| if(attributes.get_dx()->get_dim().empty()) | ||
| { | ||
| attributes.get_dx()->set_dim(attributes.get_x()->get_dim()); | ||
| } | ||
| if(attributes.get_dx()->get_stride().empty()) | ||
| { | ||
| attributes.get_dx()->set_stride(attributes.get_x()->get_stride()); | ||
| } |
There was a problem hiding this comment.
We should probably infer dy too.
There was a problem hiding this comment.
Missed that, probably because I thought that the input vectors would be known. The minimum set of known input shapes should now be x and scale.
| return _wrapper->asDescriptor<LayernormBackwardOperationDescriptor>(); | ||
| } | ||
|
|
||
| void setTensors() const |
There was a problem hiding this comment.
Should set normalized_dim_count here too.
There was a problem hiding this comment.
Done, including the relevant tests.
| namespace hipdnn_backend | ||
| { | ||
|
|
||
| void LayernormBackwardOperationDescriptor::finalize() |
There was a problem hiding this comment.
I think this should also check that mean and inv_variance are only dually present.
There was a problem hiding this comment.
Added to finalize and its tests.
There was a problem hiding this comment.
Missing the addition to this function.
There was a problem hiding this comment.
I can't see which function you mean, but I assume it was hipdnnGetOperationTypeString. I've fixed a missing case there.
| hipdnn_data_sdk::utilities::iterateAlongDimensions( | ||
| normalizedDims, [&](const std::vector<int64_t>& normIndices) { | ||
| auto fullIndices | ||
| = buildFullIndices(batchIndices, normIndices, ndim, normalizedDimCount); |
There was a problem hiding this comment.
buildFullIndices is broken for mixed convention tensors, where only some are 1-padded.
Suppose:
scale.shape = [C, H, W] // reduced-rank
mean.shape = [N, 1, 1, 1] // one-paddedAnd we have:
batchIndices.size() == 4
normIndices.size() == 3
The helper will assume both are reduced-rank, and will create:
fullIndices = [n, 0, 0, 0, c, h, w]
We could pass reduced rank indices here always, but I think it's better to modify the helper to compute batchRank = ndim - normalizedDimCount; and take batchRank indices from batchIndices, and take the last normalizedDimCount entries from normIndices.
We should also make sure these cases are tested.
There was a problem hiding this comment.
I've rewritten buildFullIndices to just take normalizedDimCount or ndim - normalizedDimCount dimensions and added some extra tests to cover odd cases.
| const auto& dims = dy.dims(); | ||
| auto ndim = static_cast<int64_t>(dims.size()); | ||
|
|
||
| if(ndim < 1) |
There was a problem hiding this comment.
For optional improved handling, consider also checking:
dy.dims() == x.dims()dx.dims() == x.dims()- scale shape is compatible with
normalizedDimCount - mean/rstd shape is compatible with batch dims
- one-padded and reduced-rank combinations are valid
Some of these may also be appropriate for pre_validate_node.
There was a problem hiding this comment.
I've added a bunch of checks to pre_validate_node and added tests for them.
| // Builds a standard LayernormBackward graph, lowers via build_operation_graph(handle), | ||
| // lifts back with fromBackendDescriptor(), and performs comprehensive field-by-field | ||
| // validation of graph data types, tensor attributes, and operation parameters. | ||
| TEST_F(IntegrationLayernormBackwardDescriptorLifting, BasicLayernormBackwardRoundTrip) |
There was a problem hiding this comment.
Verify optional tensors too.
| // After lifting, verifies tensor objects in the node attributes are the same | ||
| // shared_ptr instances as in the tensor map (pointer equality). | ||
| TEST_F(IntegrationLayernormBackwardDescriptorLifting, LayernormBackwardTensorSharingPreserved) |
There was a problem hiding this comment.
Probably worth verifying optional tensors again. I think LayernormBackwardLiftWithoutFinalization is the same too.
There was a problem hiding this comment.
Done for all relevant tests in this file.
There was a problem hiding this comment.
I think we're missing any verification that normalized_dim_count is preserved through lifting.
There was a problem hiding this comment.
I think you're right, so I've added checks to this file where relevant.
519d1d2 to
53fb612
Compare
❌ PR Check — Action Required
📖 Need help? See the Policy FAQ for details on every check and how to fix failures. |
|
🚫 Please fix the failed policies before requesting reviews. The following policy checks failed:
The |
a24b304 to
832ec00
Compare
Motivation
Generate the frontend code and implement the CPU reference for backward layernorm in HipDNN.
Technical Details
Test Plan
Build and run the
checktarget.Test Result
All new and existing tests pass.
Submission Checklist