已合并
[master][Fix] Fix static check errors detected by clang-format #5599
thickhair创建于 7月29日
[master][Fix] Fix static check errors detected by clang-format #5599
已合并
共 52 个文件变更+3446-2998
| @@ -19,25 +19,27 @@ | |||
| 19 | namespace op_api { | 19 | namespace op_api { |
| 20 | using npu_preparation = at_npu::native::OpPreparation; | 20 | using npu_preparation = at_npu::native::OpPreparation; |
| 21 | 21 | ||
| 22 | -at::Tensor npu_scaled_masked_softmax(const at::Tensor& x, const at::Tensor& mask, const at::Scalar& scale, | 22 | +at::Tensor npu_scaled_masked_softmax( |
| 23 | - bool fixed_triu_mask) | 23 | + const at::Tensor& x, |
| 24 | -{ | 24 | + const at::Tensor& mask, |
| 25 | - if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { | 25 | + const at::Scalar& scale, |
| 26 | - return acl_op::npu_scaled_masked_softmax(x, mask, scale, fixed_triu_mask); | 26 | + bool fixed_triu_mask) { |
| 27 | - } | 27 | + if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { |
| 28 | - DO_COMPATIBILITY(aclnnScaledMaskedSoftmax, acl_op::npu_scaled_masked_softmax(x, mask, scale, fixed_triu_mask)); | 28 | + return acl_op::npu_scaled_masked_softmax(x, mask, scale, fixed_triu_mask); |
| 29 | - double scale_value = 1.0; | 29 | + } |
| 30 | - if (scale.isFloatingPoint()) { | 30 | + DO_COMPATIBILITY(aclnnScaledMaskedSoftmax, acl_op::npu_scaled_masked_softmax(x, mask, scale, fixed_triu_mask)); |
| 31 | - scale_value = scale.to<double>(); | 31 | + double scale_value = 1.0; |
| 32 | - } else if (scale.isIntegral(true)) { | 32 | + if (scale.isFloatingPoint()) { |
| 33 | - scale_value = static_cast<double>(scale.to<int64_t>()); | 33 | + scale_value = scale.to<double>(); |
| 34 | - } else { | 34 | + } else if (scale.isIntegral(true)) { |
| 35 | - TORCH_CHECK(false, "scaled_masked_softmax expects scale to be float or int", OPS_ERROR(ErrCode::TYPE)); | 35 | + scale_value = static_cast<double>(scale.to<int64_t>()); |
| 36 | - } | 36 | + } else { |
| 37 | + TORCH_CHECK(false, "scaled_masked_softmax expects scale to be float or int", OPS_ERROR(ErrCode::TYPE)); | ||
| 38 | + } | ||
| 37 | 39 | ||
| 38 | - at::Tensor result = npu_preparation::apply_tensor_without_format(x.sizes(), x.options()); | 40 | + at::Tensor result = npu_preparation::apply_tensor_without_format(x.sizes(), x.options()); |
| 39 | - EXEC_NPU_CMD(aclnnScaledMaskedSoftmax, x, mask, scale_value, fixed_triu_mask, result); | 41 | + EXEC_NPU_CMD(aclnnScaledMaskedSoftmax, x, mask, scale_value, fixed_triu_mask, result); |
| 40 | - return result; | 42 | + return result; |
| 41 | } | 43 | } |
| 42 | 44 | ||
| 43 | at::Tensor npu_scaled_masked_softmax_backward( | 45 | at::Tensor npu_scaled_masked_softmax_backward( |
| @@ -45,23 +47,24 @@ at::Tensor npu_scaled_masked_softmax_backward( | |||
| 45 | const at::Tensor& y, | 47 | const at::Tensor& y, |
| 46 | const at::Tensor& mask, | 48 | const at::Tensor& mask, |
| 47 | const at::Scalar& scale, | 49 | const at::Scalar& scale, |
| 48 | - bool fixed_triu_mask) | 50 | + bool fixed_triu_mask) { |
| 49 | -{ | 51 | + if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { |
| 50 | - if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { | 52 | + return acl_op::npu_scaled_masked_softmax_backward(y_grad, y, mask, scale, fixed_triu_mask); |
| 51 | - return acl_op::npu_scaled_masked_softmax_backward(y_grad, y, mask, scale, fixed_triu_mask); | 53 | + } |
| 52 | - } | 54 | + DO_COMPATIBILITY( |
| 53 | - DO_COMPATIBILITY(aclnnScaledMaskedSoftmaxBackward, acl_op::npu_scaled_masked_softmax_backward(y_grad, y, mask, scale, fixed_triu_mask)); | 55 | + aclnnScaledMaskedSoftmaxBackward, |
| 54 | - double scale_value = 1.0; | 56 | + acl_op::npu_scaled_masked_softmax_backward(y_grad, y, mask, scale, fixed_triu_mask)); |
| 55 | - if (scale.isFloatingPoint()) { | 57 | + double scale_value = 1.0; |
| 56 | - scale_value = scale.to<double>(); | 58 | + if (scale.isFloatingPoint()) { |
| 57 | - } else if (scale.isIntegral(true)) { | 59 | + scale_value = scale.to<double>(); |
| 58 | - scale_value = static_cast<double>(scale.to<int64_t>()); | 60 | + } else if (scale.isIntegral(true)) { |
| 59 | - } else { | 61 | + scale_value = static_cast<double>(scale.to<int64_t>()); |
| 60 | - TORCH_CHECK(false, "scaled_masked_softmax_backward expects scale to be float or int", OPS_ERROR(ErrCode::TYPE)); | 62 | + } else { |
| 61 | - } | 63 | + TORCH_CHECK(false, "scaled_masked_softmax_backward expects scale to be float or int", OPS_ERROR(ErrCode::TYPE)); |
| 64 | + } | ||
| 62 | 65 | ||
| 63 | - at::Tensor result = npu_preparation::apply_tensor_without_format(y_grad.sizes(), y_grad.options()); | 66 | + at::Tensor result = npu_preparation::apply_tensor_without_format(y_grad.sizes(), y_grad.options()); |
| 64 | - EXEC_NPU_CMD(aclnnScaledMaskedSoftmaxBackward, y_grad, y, mask, scale_value, fixed_triu_mask, result); | 67 | + EXEC_NPU_CMD(aclnnScaledMaskedSoftmaxBackward, y_grad, y, mask, scale_value, fixed_triu_mask, result); |
| 65 | - return result; | 68 | + return result; |
| 66 | } | 69 | } |
| 67 | -} | 70 | +} // namespace op_api |
| @@ -18,7 +18,6 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | 20 | ||
| 21 | - | ||
| 22 | namespace op_api { | 21 | namespace op_api { |
| 23 | constexpr size_t LAST_SECOND_DIM_INDEX = 2; | 22 | constexpr size_t LAST_SECOND_DIM_INDEX = 2; |
| 24 | constexpr int64_t PERGROUP_DIM_NUM = 2; | 23 | constexpr int64_t PERGROUP_DIM_NUM = 2; |
| @@ -28,414 +27,501 @@ static const size_t A8W4_GROUP_DIM = 3; | |||
| 28 | static const size_t A8W4_INPUT_DIM = 2; | 27 | static const size_t A8W4_INPUT_DIM = 2; |
| 29 | using npu_preparation = at_npu::native::OpPreparation; | 28 | using npu_preparation = at_npu::native::OpPreparation; |
| 30 | 29 | ||
| 31 | -bool static is_transpose_last_two_dims(const at::Tensor &tensor) | 30 | +bool static is_transpose_last_two_dims(const at::Tensor& tensor) { |
| 32 | -{ | 31 | + if (tensor.dim() < 2 || tensor.dim() > 6) { |
| 33 | - if (tensor.dim() < 2 || tensor.dim() > 6) { | 32 | + return false; |
| 33 | + } | ||
| 34 | + int64_t dim1 = tensor.dim() - 1; | ||
| 35 | + int64_t dim2 = tensor.dim() - 2; | ||
| 36 | + if (tensor.stride(dim2) == 1 && tensor.stride(dim1) == tensor.size(dim2)) { | ||
| 37 | + int64_t tmpNxD = tensor.size(dim1) * tensor.size(dim2); | ||
| 38 | + for (int64_t batchDim = tensor.dim() - 3; batchDim >= 0; batchDim--) { | ||
| 39 | + if (tensor.stride(batchDim) != tmpNxD) { | ||
| 34 | return false; | 40 | return false; |
| 41 | + } | ||
| 42 | + tmpNxD *= tensor.size(batchDim); | ||
| 35 | } | 43 | } |
| 36 | - int64_t dim1 = tensor.dim() - 1; | 44 | + if (tensor.size(dim1) == 1 && tensor.size(dim2) == 1) { |
| 37 | - int64_t dim2 = tensor.dim() - 2; | 45 | + return false; |
| 38 | - if (tensor.stride(dim2) == 1 && tensor.stride(dim1) == tensor.size(dim2)) { | ||
| 39 | - int64_t tmpNxD = tensor.size(dim1) * tensor.size(dim2); | ||
| 40 | - for (int64_t batchDim = tensor.dim() - 3; batchDim >= 0; batchDim--) { | ||
| 41 | - if (tensor.stride(batchDim) != tmpNxD) { | ||
| 42 | - return false; | ||
| 43 | - } | ||
| 44 | - tmpNxD *= tensor.size(batchDim); | ||
| 45 | - } | ||
| 46 | - if (tensor.size(dim1) == 1 && tensor.size(dim2) == 1) { | ||
| 47 | - return false; | ||
| 48 | - } | ||
| 49 | - return true; | ||
| 50 | } | 46 | } |
| 51 | - return false; | 47 | + return true; |
| 48 | + } | ||
| 49 | + return false; | ||
| 52 | } | 50 | } |
| 53 | 51 | ||
| 54 | -static bool is_transpose_certain_two_dims(const at::Tensor &tensor, int64_t dim) | 52 | +static bool is_transpose_certain_two_dims(const at::Tensor& tensor, int64_t dim) { |
| 55 | -{ | 53 | + return tensor.stride(dim + 1) == tensor.stride(dim) * tensor.size(dim); |
| 56 | - return tensor.stride(dim + 1) == tensor.stride(dim) * tensor.size(dim); | ||
| 57 | } | 54 | } |
| 58 | 55 | ||
| 59 | -static bool is_x_scale_same_transpose(const at::Tensor &x, const at::Tensor &scale, int64_t dim_x, int64_t dim_scale) | 56 | +static bool is_x_scale_same_transpose(const at::Tensor& x, const at::Tensor& scale, int64_t dim_x, int64_t dim_scale) { |
| 60 | -{ | 57 | + if (x.dim() < dim_x + 2 || scale.dim() < dim_scale + 2) { // make sure dims after the start dim are no less than 2 |
| 61 | - if (x.dim() < dim_x + 2 || scale.dim() < dim_scale + 2) { // make sure dims after the start dim are no less than 2 | 58 | + return true; |
| 62 | - return true; | 59 | + } |
| 63 | - } | 60 | + if (x.size(dim_x) == 1 && x.size(dim_x + 1) == 1) { |
| 64 | - if (x.size(dim_x) == 1 && x.size(dim_x + 1)== 1) { | 61 | + return true; |
| 65 | - return true; | 62 | + } |
| 66 | - } | 63 | + if (scale.size(dim_scale) == 1 && scale.size(dim_scale + 1) == 1) { |
| 67 | - if (scale.size(dim_scale) == 1 && scale.size(dim_scale + 1)== 1) { | 64 | + return true; |
| 68 | - return true; | 65 | + } |
| 69 | - } | 66 | + bool x_trans = is_transpose_certain_two_dims(x, dim_x); |
| 70 | - bool x_trans = is_transpose_certain_two_dims(x, dim_x); | 67 | + bool scale_trans = is_transpose_certain_two_dims(scale, dim_scale); |
| 71 | - bool scale_trans = is_transpose_certain_two_dims(scale, dim_scale); | 68 | + if (x_trans == scale_trans) { |
| 72 | - if (x_trans == scale_trans) { | 69 | + return true; |
| 73 | - return true; | 70 | + } |
| 74 | - } | 71 | + return false; |
| 75 | - return false; | ||
| 76 | } | 72 | } |
| 77 | -static bool is_nz_format(const at::Tensor& x2) | 73 | +static bool is_nz_format(const at::Tensor& x2) { |
| 78 | -{ | 74 | + const torch_npu::NPUStorageDesc& tensor_desc = torch_npu::NPUBridge::GetNpuStorageImpl(x2)->npu_desc_; |
| 79 | - const torch_npu::NPUStorageDesc &tensor_desc = | 75 | + return tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ || tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_4 || |
| 80 | - torch_npu::NPUBridge::GetNpuStorageImpl(x2)->npu_desc_; | 76 | + tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_16; |
| 81 | - return tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ || | ||
| 82 | - tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_4 || | ||
| 83 | - tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_16; | ||
| 84 | } | 77 | } |
| 85 | 78 | ||
| 86 | -static uint64_t infer_out_batch_shape(const at::Tensor &x1, const at::Tensor &x2, std::vector<uint64_t> &batch_record) | 79 | +static uint64_t infer_out_batch_shape(const at::Tensor& x1, const at::Tensor& x2, std::vector<uint64_t>& batch_record) { |
| 87 | -{ | 80 | + TORCH_CHECK( |
| 88 | - TORCH_CHECK(at_npu::native::FormatHelper::IsBaseFormatType(x2) || is_nz_format(x2), | 81 | + at_npu::native::FormatHelper::IsBaseFormatType(x2) || is_nz_format(x2), |
| 89 | - "x2 should be in the original image format or nz format, but it is ", | 82 | + "x2 should be in the original image format or nz format, but it is ", |
| 90 | - npu_preparation::get_tensor_npu_format(x2), OPS_ERROR(ErrCode::PARAM)); | 83 | + npu_preparation::get_tensor_npu_format(x2), |
| 91 | - uint64_t batch_val = 1; | 84 | + OPS_ERROR(ErrCode::PARAM)); |
| 92 | - auto x1_dim_num = x1.dim(); | 85 | + uint64_t batch_val = 1; |
| 93 | - auto x2_dim_num = x2.dim(); | 86 | + auto x1_dim_num = x1.dim(); |
| 94 | - auto out_dim_num = std::max(x1_dim_num, x2_dim_num); | 87 | + auto x2_dim_num = x2.dim(); |
| 95 | - auto &shape_long = x1_dim_num > x2_dim_num ? x1 : x2; | 88 | + auto out_dim_num = std::max(x1_dim_num, x2_dim_num); |
| 96 | - auto &shape_short = x1_dim_num > x2_dim_num ? x2 : x1; | 89 | + auto& shape_long = x1_dim_num > x2_dim_num ? x1 : x2; |
| 97 | - int64_t vaild_offset = out_dim_num - std::min(x1_dim_num, x2_dim_num); | 90 | + auto& shape_short = x1_dim_num > x2_dim_num ? x2 : x1; |
| 98 | - for (int64_t i = 0; i < out_dim_num - LAST_SECOND_DIM_INDEX; i++) { | 91 | + int64_t vaild_offset = out_dim_num - std::min(x1_dim_num, x2_dim_num); |
| 99 | - auto short_dim = i < vaild_offset ? 1 : shape_short.size(i - vaild_offset); | 92 | + for (int64_t i = 0; i < out_dim_num - LAST_SECOND_DIM_INDEX; i++) { |
| 100 | - auto long_dim = shape_long.size(i); | 93 | + auto short_dim = i < vaild_offset ? 1 : shape_short.size(i - vaild_offset); |
| 101 | - TORCH_CHECK(!(short_dim > 1 && long_dim > 1 && short_dim != long_dim), | 94 | + auto long_dim = shape_long.size(i); |
| 102 | - "the x1 shape and x2 shape not supported for broadcast, the short_dim is ", | 95 | + TORCH_CHECK( |
| 103 | - short_dim, " and the long_dim is ", long_dim, OPS_ERROR(ErrCode::PARAM)); | 96 | + !(short_dim > 1 && long_dim > 1 && short_dim != long_dim), |
| 104 | - uint64_t cur_batch_value = static_cast<uint64_t>(std::max(short_dim, long_dim)); | 97 | + "the x1 shape and x2 shape not supported for broadcast, the short_dim is ", |
| 105 | - batch_val = batch_val * cur_batch_value; | 98 | + short_dim, |
| 106 | - batch_record.push_back(cur_batch_value); | 99 | + " and the long_dim is ", |
| 107 | - } | 100 | + long_dim, |
| 108 | - return batch_val; | 101 | + OPS_ERROR(ErrCode::PARAM)); |
| 102 | + uint64_t cur_batch_value = static_cast<uint64_t>(std::max(short_dim, long_dim)); | ||
| 103 | + batch_val = batch_val * cur_batch_value; | ||
| 104 | + batch_record.push_back(cur_batch_value); | ||
| 105 | + } | ||
| 106 | + return batch_val; | ||
| 109 | } | 107 | } |
| 110 | 108 | ||
| 111 | -static int64_t check_and_get_groups(at::IntArrayRef group_size_list) | 109 | +static int64_t check_and_get_groups(at::IntArrayRef group_size_list) { |
| 112 | -{ | 110 | + int64_t groups = 0; |
| 113 | - int64_t groups = 0; | 111 | + if (group_size_list.empty()) { |
| 114 | - if (group_size_list.empty()) { | ||
| 115 | - return groups; | ||
| 116 | - } | ||
| 117 | - size_t group_dim = group_size_list.size(); | ||
| 118 | - TORCH_CHECK(group_dim == A8W4_GROUP_DIM, "group_sizes only support input with three elements, but got ", | ||
| 119 | - group_dim, OPS_ERROR(ErrCode::PARAM)); | ||
| 120 | - int64_t group_m = static_cast<int64_t>(group_size_list[0]); | ||
| 121 | - int64_t group_n = static_cast<int64_t>(group_size_list[1]); | ||
| 122 | - int64_t group_k = static_cast<int64_t>(group_size_list[2]); | ||
| 123 | - bool invalid_group_param = ((group_m <= GROUP_MAX && group_m >= 0) | ||
| 124 | - && (group_n <= GROUP_MAX && group_n >= 0) | ||
| 125 | - && (group_k <= GROUP_MAX && group_k >= 0)); | ||
| 126 | - TORCH_CHECK(invalid_group_param, "group param value must conform to range [0, 65535]", OPS_ERROR(ErrCode::VALUE)); | ||
| 127 | - groups = static_cast<int64_t>((static_cast<uint64_t>(group_m) << 32) + (static_cast<uint64_t>(group_n) << 16) + | ||
| 128 | - (static_cast<uint64_t>(group_k))); | ||
| 129 | return groups; | 112 | return groups; |
| 113 | + } | ||
| 114 | + size_t group_dim = group_size_list.size(); | ||
| 115 | + TORCH_CHECK( | ||
| 116 | + group_dim == A8W4_GROUP_DIM, | ||
| 117 | + "group_sizes only support input with three elements, but got ", | ||
| 118 | + group_dim, | ||
| 119 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 120 | + int64_t group_m = static_cast<int64_t>(group_size_list[0]); | ||
| 121 | + int64_t group_n = static_cast<int64_t>(group_size_list[1]); | ||
| 122 | + int64_t group_k = static_cast<int64_t>(group_size_list[2]); | ||
| 123 | + bool invalid_group_param = | ||
| 124 | + ((group_m <= GROUP_MAX && group_m >= 0) && (group_n <= GROUP_MAX && group_n >= 0) && | ||
| 125 | + (group_k <= GROUP_MAX && group_k >= 0)); | ||
| 126 | + TORCH_CHECK(invalid_group_param, "group param value must conform to range [0, 65535]", OPS_ERROR(ErrCode::VALUE)); | ||
| 127 | + groups = static_cast<int64_t>( | ||
| 128 | + (static_cast<uint64_t>(group_m) << 32) + (static_cast<uint64_t>(group_n) << 16) + | ||
| 129 | + (static_cast<uint64_t>(group_k))); | ||
| 130 | + return groups; | ||
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | static const std::map<c10::ScalarType, int64_t> SCALAR_TO_INT_TYPE_MAP = { | 133 | static const std::map<c10::ScalarType, int64_t> SCALAR_TO_INT_TYPE_MAP = { |
| 133 | - {c10::ScalarType::Char, static_cast<int64_t>(at::kChar)}, /**< int8 */ | 134 | + {c10::ScalarType::Char, static_cast<int64_t>(at::kChar)}, /**< int8 */ |
| 134 | - {c10::ScalarType::Int, static_cast<int64_t>(at::kInt)}, /**< int32 */ | 135 | + {c10::ScalarType::Int, static_cast<int64_t>(at::kInt)}, /**< int32 */ |
| 135 | - {c10::ScalarType::BFloat16, static_cast<int64_t>(at::kBFloat16)}, /**< bfp16 */ | 136 | + {c10::ScalarType::BFloat16, static_cast<int64_t>(at::kBFloat16)}, /**< bfp16 */ |
| 136 | - {c10::ScalarType::Half, static_cast<int64_t>(at::kHalf)}, /**< fp16 */ | 137 | + {c10::ScalarType::Half, static_cast<int64_t>(at::kHalf)}, /**< fp16 */ |
| 137 | - {c10::ScalarType::Float, static_cast<int64_t>(at::kFloat)}, /**< fp32 */ | 138 | + {c10::ScalarType::Float, static_cast<int64_t>(at::kFloat)}, /**< fp32 */ |
| 138 | 139 | ||
| 139 | - {c10::ScalarType::Float8_e4m3fn, static_cast<int64_t>(at::kFloat8_e4m3fn)}, /**< fp8e4m3 */ | 140 | + {c10::ScalarType::Float8_e4m3fn, static_cast<int64_t>(at::kFloat8_e4m3fn)}, /**< fp8e4m3 */ |
| 140 | - {c10::ScalarType::Float8_e5m2, static_cast<int64_t>(at::kFloat8_e5m2)}, /**< fp8e5m2 */ | 141 | + {c10::ScalarType::Float8_e5m2, static_cast<int64_t>(at::kFloat8_e5m2)}, /**< fp8e5m2 */ |
| 141 | - {c10::ScalarType::Byte, static_cast<int64_t>(c10_npu::DType::HIFLOAT8)} /**< hif8 */ | 142 | + {c10::ScalarType::Byte, static_cast<int64_t>(c10_npu::DType::HIFLOAT8)} /**< hif8 */ |
| 142 | }; | 143 | }; |
| 143 | 144 | ||
| 144 | -static c10::optional<int64_t> ToIntType(const std::optional<c10::ScalarType> &torchType) { | 145 | +static c10::optional<int64_t> ToIntType(const std::optional<c10::ScalarType>& torchType) { |
| 145 | - c10::optional<int64_t> int_type = c10::nullopt; | 146 | + c10::optional<int64_t> int_type = c10::nullopt; |
| 146 | - if (torchType.has_value()) { | 147 | + if (torchType.has_value()) { |
| 147 | - const auto &it = SCALAR_TO_INT_TYPE_MAP.find(torchType.value()); | 148 | + const auto& it = SCALAR_TO_INT_TYPE_MAP.find(torchType.value()); |
| 148 | - if (it != SCALAR_TO_INT_TYPE_MAP.cend()) { | 149 | + if (it != SCALAR_TO_INT_TYPE_MAP.cend()) { |
| 149 | - int_type = c10::make_optional(it->second); | 150 | + int_type = c10::make_optional(it->second); |
| 150 | - } | ||
| 151 | } | 151 | } |
| 152 | - return int_type; | 152 | + } |
| 153 | + return int_type; | ||
| 153 | } | 154 | } |
| 154 | 155 | ||
| 155 | -at::Tensor _scaled_mm(const at::Tensor &mat_a, | 156 | +at::Tensor _scaled_mm( |
| 156 | - const at::Tensor &mat_b, | 157 | + const at::Tensor& mat_a, |
| 157 | - const at::Tensor &scale_a, | 158 | + const at::Tensor& mat_b, |
| 158 | - const at::Tensor &scale_b, | 159 | + const at::Tensor& scale_a, |
| 160 | + const at::Tensor& scale_b, | ||
| 159 | const std::optional<at::Tensor>& bias, | 161 | const std::optional<at::Tensor>& bias, |
| 160 | const std::optional<at::Tensor>& scale_result, // 对result做scale,仅当output为float8时才有用, | 162 | const std::optional<at::Tensor>& scale_result, // 对result做scale,仅当output为float8时才有用, |
| 161 | - std::optional<c10::ScalarType> out_dtype, // 当前不支持float8 | 163 | + std::optional<c10::ScalarType> out_dtype, // 当前不支持float8 |
| 162 | bool use_fast_accum) | 164 | bool use_fast_accum) |
| 163 | 165 | ||
| 164 | { | 166 | { |
| 167 | + // check A5 | ||
| 168 | + TORCH_CHECK( | ||
| 169 | + c10_npu::GetSocVersion() >= c10_npu::SocVersion::Ascend950, | ||
| 170 | + "_scaled_mm is supported only on the Ascend950 platform and after.", | ||
| 171 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 165 | 172 | ||
| 166 | - // check A5 | 173 | + // Check data types: mat_a and mat_b must be float8 type |
| 167 | - TORCH_CHECK(c10_npu::GetSocVersion() >= c10_npu::SocVersion::Ascend950, | 174 | + TORCH_CHECK( |
| 168 | - "_scaled_mm is supported only on the Ascend950 platform and after.", OPS_ERROR(ErrCode::PARAM)); | 175 | + mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn || mat_a.scalar_type() == c10::ScalarType::Float8_e5m2, |
| 176 | + "mat_a must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", | ||
| 177 | + mat_a.scalar_type(), | ||
| 178 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 179 | + TORCH_CHECK( | ||
| 180 | + mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn || mat_b.scalar_type() == c10::ScalarType::Float8_e5m2, | ||
| 181 | + "mat_b must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", | ||
| 182 | + mat_b.scalar_type(), | ||
| 183 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 169 | 184 | ||
| 170 | - // Check data types: mat_a and mat_b must be float8 type | 185 | + // Check multiplication of two Float8_e5m2 is not supported (reference: _scaled_mm_out_cuda) |
| 171 | - TORCH_CHECK(mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn || | 186 | + TORCH_CHECK( |
| 172 | - mat_a.scalar_type() == c10::ScalarType::Float8_e5m2, | 187 | + mat_a.scalar_type() != c10::ScalarType::Float8_e5m2 || mat_b.scalar_type() != c10::ScalarType::Float8_e5m2, |
| 173 | - "mat_a must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", mat_a.scalar_type(), | 188 | + "Multiplication of two Float8_e5m2 matrices is not supported", |
| 174 | - OPS_ERROR(ErrCode::TYPE)); | 189 | + OPS_ERROR(ErrCode::TYPE)); |
| 175 | - TORCH_CHECK(mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn || | ||
| 176 | - mat_b.scalar_type() == c10::ScalarType::Float8_e5m2, | ||
| 177 | - "mat_b must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", mat_b.scalar_type(), | ||
| 178 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 179 | 190 | ||
| 180 | - // Check multiplication of two Float8_e5m2 is not supported (reference: _scaled_mm_out_cuda) | 191 | + // Check data types: scale_a and scale_b must be float32 or float8_e8m0 type |
| 181 | - TORCH_CHECK(mat_a.scalar_type() != c10::ScalarType::Float8_e5m2 || | 192 | + TORCH_CHECK( |
| 182 | - mat_b.scalar_type() != c10::ScalarType::Float8_e5m2, | 193 | + scale_a.scalar_type() == c10::ScalarType::Float || |
| 183 | - "Multiplication of two Float8_e5m2 matrices is not supported", | 194 | + scale_a.scalar_type() == |
| 184 | - OPS_ERROR(ErrCode::TYPE)); | 195 | + npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), |
| 196 | + "scale_a must be float32 or float8_e8m0 type, but got ", | ||
| 197 | + scale_a.scalar_type(), | ||
| 198 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 199 | + TORCH_CHECK( | ||
| 200 | + scale_b.scalar_type() == c10::ScalarType::Float || | ||
| 201 | + scale_b.scalar_type() == | ||
| 202 | + npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), | ||
| 203 | + "scale_b must be float32 or float8_e8m0 type, but got ", | ||
| 204 | + scale_b.scalar_type(), | ||
| 205 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 185 | 206 | ||
| 186 | - // Check data types: scale_a and scale_b must be float32 or float8_e8m0 type | 207 | + // Check bias (reference: _scaled_mm_out_cuda) |
| 187 | - TORCH_CHECK(scale_a.scalar_type() == c10::ScalarType::Float || | 208 | + if (bias.has_value()) { |
| 188 | - scale_a.scalar_type() == npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), | 209 | + TORCH_CHECK( |
| 189 | - "scale_a must be float32 or float8_e8m0 type, but got ", scale_a.scalar_type(), | 210 | + bias->numel() == mat_b.sizes()[1], |
| 211 | + "Bias must be size ", | ||
| 212 | + mat_b.sizes()[1], | ||
| 213 | + " but got ", | ||
| 214 | + bias->numel(), | ||
| 215 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 216 | + // Check out_dtype vs bias compatibility | ||
| 217 | + auto out_dtype_value = out_dtype.value_or(c10::ScalarType::BFloat16); | ||
| 218 | + TORCH_CHECK( | ||
| 219 | + out_dtype_value != c10::ScalarType::Float, | ||
| 220 | + "Bias is not supported when out_dtype is set to Float32", | ||
| 190 | OPS_ERROR(ErrCode::TYPE)); | 221 | OPS_ERROR(ErrCode::TYPE)); |
| 191 | - TORCH_CHECK(scale_b.scalar_type() == c10::ScalarType::Float || | 222 | + TORCH_CHECK( |
| 192 | - scale_b.scalar_type() == npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), | 223 | + bias->scalar_type() == c10::ScalarType::BFloat16 || bias->scalar_type() == c10::ScalarType::Half, |
| 193 | - "scale_b must be float32 or float8_e8m0 type, but got ", scale_b.scalar_type(), | 224 | + "Bias must be BFloat16 or Half, but got ", |
| 225 | + bias->scalar_type(), | ||
| 194 | OPS_ERROR(ErrCode::TYPE)); | 226 | OPS_ERROR(ErrCode::TYPE)); |
| 227 | + TORCH_CHECK( | ||
| 228 | + (out_dtype_value != c10::ScalarType::Float && out_dtype_value != c10::ScalarType::BFloat16) || | ||
| 229 | + bias->scalar_type() == c10::ScalarType::BFloat16, | ||
| 230 | + "Bias must be BFloat16 to compute ", | ||
| 231 | + out_dtype_value, | ||
| 232 | + " output, but got ", | ||
| 233 | + bias->scalar_type(), | ||
| 234 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 235 | + TORCH_CHECK( | ||
| 236 | + out_dtype_value != c10::ScalarType::Half || bias->scalar_type() == c10::ScalarType::Half, | ||
| 237 | + "Bias must be Float16 to compute ", | ||
| 238 | + out_dtype_value, | ||
| 239 | + " output, but got ", | ||
| 240 | + bias->scalar_type(), | ||
| 241 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 242 | + } | ||
| 195 | 243 | ||
| 196 | - // Check bias (reference: _scaled_mm_out_cuda) | 244 | + // Check scale_result: currently only supports null/empty because output float8 is not supported |
| 197 | - if (bias.has_value()) { | 245 | + TORCH_CHECK( |
| 198 | - TORCH_CHECK(bias->numel() == mat_b.sizes()[1], | 246 | + !scale_result.has_value() || scale_result == c10::nullopt, |
| 199 | - "Bias must be size ", mat_b.sizes()[1], " but got ", bias->numel(), | 247 | + "scale_result is not supported currently, as output float8 type is not enabled. " |
| 200 | - OPS_ERROR(ErrCode::PARAM)); | 248 | + "scale_result is only utilized when output is float8 type.", |
| 201 | - // Check out_dtype vs bias compatibility | 249 | + OPS_ERROR(ErrCode::NOT_SUPPORT)); |
| 202 | - auto out_dtype_value = out_dtype.value_or(c10::ScalarType::BFloat16); | 250 | + |
| 203 | - TORCH_CHECK(out_dtype_value != c10::ScalarType::Float, | 251 | + // Check out_dtype: currently only supports Float32, BFloat16, and Float16 |
| 204 | - "Bias is not supported when out_dtype is set to Float32", | 252 | + if (out_dtype.has_value()) { |
| 205 | - OPS_ERROR(ErrCode::TYPE)); | 253 | + TORCH_CHECK( |
| 206 | - TORCH_CHECK(bias->scalar_type() == c10::ScalarType::BFloat16 || | 254 | + out_dtype.value() == c10::ScalarType::Float || out_dtype.value() == c10::ScalarType::BFloat16 || |
| 207 | - bias->scalar_type() == c10::ScalarType::Half, | 255 | + out_dtype.value() == c10::ScalarType::Half, |
| 208 | - "Bias must be BFloat16 or Half, but got ", bias->scalar_type(), | 256 | + "out_dtype must be Float32, BFloat16, or Float16, but got ", |
| 209 | - OPS_ERROR(ErrCode::TYPE)); | 257 | + out_dtype.value(), |
| 210 | - TORCH_CHECK((out_dtype_value != c10::ScalarType::Float && | 258 | + OPS_ERROR(ErrCode::TYPE)); |
| 211 | - out_dtype_value != c10::ScalarType::BFloat16) || | 259 | + } |
| 212 | - bias->scalar_type() == c10::ScalarType::BFloat16, | 260 | + |
| 213 | - "Bias must be BFloat16 to compute ", out_dtype_value, | 261 | + // Check sizes |
| 214 | - " output, but got ", bias->scalar_type(), | 262 | + TORCH_CHECK(mat_a.dim() == 2, "mat_a must be a matrix, please check mat_a dim num.", OPS_ERROR(ErrCode::PARAM)); |
| 215 | - OPS_ERROR(ErrCode::TYPE)); | 263 | + TORCH_CHECK(mat_b.dim() == 2, "mat_b must be a matrix, please check mat_b dim num.", OPS_ERROR(ErrCode::PARAM)); |
| 216 | - TORCH_CHECK(out_dtype_value != c10::ScalarType::Half || | 264 | + TORCH_CHECK( |
| 217 | - bias->scalar_type() == c10::ScalarType::Half, | 265 | + mat_a.sizes()[1] == mat_b.sizes()[0], |
| 218 | - "Bias must be Float16 to compute ", out_dtype_value, | 266 | + "mat_a and mat_b shapes cannot be multiplied (", |
| 219 | - " output, but got ", bias->scalar_type(), | 267 | + mat_a.sizes()[0], |
| 220 | - OPS_ERROR(ErrCode::TYPE)); | 268 | + "x", |
| 269 | + mat_b.sizes()[1], | ||
| 270 | + " and ", | ||
| 271 | + mat_b.sizes()[0], | ||
| 272 | + "x", | ||
| 273 | + mat_b.sizes()[1], | ||
| 274 | + ")", | ||
| 275 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 276 | + | ||
| 277 | + //////////////rowwise transfer////////////// | ||
| 278 | + at::Tensor processed_scale_a = scale_a; | ||
| 279 | + at::Tensor processed_scale_b = scale_b; | ||
| 280 | + if (mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn && mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn && | ||
| 281 | + scale_a.scalar_type() == c10::ScalarType::Float && scale_b.scalar_type() == c10::ScalarType::Float) { | ||
| 282 | + if (scale_a.dim() == 2 && scale_a.sizes()[1] == 1 && scale_b.dim() == 2 && scale_b.sizes()[0] == 1) { | ||
| 283 | + TORCH_CHECK(mat_a.stride(1) == 1, "mat_a must be contiguous in last dim"); | ||
| 284 | + TORCH_CHECK(mat_b.stride(0) == 1, "mat_b must be contiguous in first dim"); | ||
| 285 | + processed_scale_a = scale_a.squeeze(-1).contiguous(); | ||
| 286 | + processed_scale_b = scale_b.squeeze(0); | ||
| 221 | } | 287 | } |
| 288 | + } | ||
| 222 | 289 | ||
| 290 | + //////////////parameters transfer////////////// | ||
| 291 | + at::Tensor x1 = mat_a; | ||
| 292 | + at::Tensor x2 = mat_b; | ||
| 293 | + c10::optional<at::Tensor> pertoken_scale = processed_scale_a; | ||
| 294 | + at::Tensor scale = processed_scale_b; | ||
| 295 | + c10::optional<int64_t> scale_dtype = c10::nullopt; // scale_b.scalar_type() | ||
| 223 | 296 | ||
| 224 | - // Check scale_result: currently only supports null/empty because output float8 is not supported | 297 | + c10::optional<int64_t> output_dtype = ToIntType(out_dtype); |
| 225 | - TORCH_CHECK(!scale_result.has_value() || scale_result == c10::nullopt, | 298 | + c10::optional<at::Tensor> offset = c10::nullopt; |
| 226 | - "scale_result is not supported currently, as output float8 type is not enabled. " | 299 | + c10::optional<int64_t> x1_dtype = c10::nullopt; |
| 227 | - "scale_result is only utilized when output is float8 type.", | 300 | + c10::optional<int64_t> x2_dtype = c10::nullopt; |
| 228 | - OPS_ERROR(ErrCode::NOT_SUPPORT)); | 301 | + c10::optional<int64_t> pertoken_scale_dtype = c10::nullopt; |
| 302 | + c10::OptionalIntArrayRef group_sizes = c10::nullopt; | ||
| 303 | + c10::optional<at::Tensor> y_scale = c10::nullopt; | ||
| 229 | 304 | ||
| 230 | - // Check out_dtype: currently only supports Float32, BFloat16, and Float16 | 305 | + ///////////////////////////////////////////npu_quant_matmul////////////////////////////////////// |
| 231 | - if (out_dtype.has_value()) { | 306 | + if (is_nz_format(x2)) { |
| 232 | - TORCH_CHECK(out_dtype.value() == c10::ScalarType::Float || | 307 | + static const bool is_quant_matmul_weight_nz_available = check_aclnn_kernel_available("aclnnQuantMatmulWeightNz"); |
| 233 | - out_dtype.value() == c10::ScalarType::BFloat16 || | 308 | + TORCH_CHECK( |
| 234 | - out_dtype.value() == c10::ScalarType::Half, | 309 | + is_quant_matmul_weight_nz_available, |
| 235 | - "out_dtype must be Float32, BFloat16, or Float16, but got ", out_dtype.value(), | 310 | + "Get aclnnQuantMatmulWeightNz or aclnnQuantMatmulWeightNzGetWorkspaceSize failed, only " |
| 236 | - OPS_ERROR(ErrCode::TYPE)); | 311 | + "aclnnQuantMatmulWeightNz support X2's format is nz, please upgrade CANN.", |
| 237 | - } | 312 | + OPS_ERROR(ErrCode::PARAM)); |
| 238 | - | 313 | + } else { |
| 239 | - | 314 | + static const bool is_quant_matmul_v5_available = check_aclnn_kernel_available("aclnnQuantMatmulV5"); |
| 240 | - // Check sizes | 315 | + TORCH_CHECK( |
| 241 | - TORCH_CHECK(mat_a.dim() == 2, "mat_a must be a matrix, please check mat_a dim num." ,OPS_ERROR(ErrCode::PARAM)); | 316 | + is_quant_matmul_v5_available, |
| 242 | - TORCH_CHECK(mat_b.dim() == 2, "mat_b must be a matrix, please check mat_b dim num." ,OPS_ERROR(ErrCode::PARAM)); | 317 | + "Get aclnnQuantMatmulV5 or aclnnQuantMatmulV5 failed, only " |
| 243 | - TORCH_CHECK(mat_a.sizes()[1] == mat_b.sizes()[0], "mat_a and mat_b shapes cannot be multiplied (",mat_a.sizes()[0], | 318 | + "aclnnQuantMatmulV5 support A8W4, please upgrade CANN.", |
| 244 | - "x", mat_b.sizes()[1], " and ", mat_b.sizes()[0], "x", mat_b.sizes()[1], ")", OPS_ERROR(ErrCode::PARAM)); | 319 | + OPS_ERROR(ErrCode::TYPE)); |
| 245 | - | 320 | + } |
| 246 | - | 321 | + bool is_a8W4_int = x1.dtype() == at::kChar && x2.dtype() == at::kInt; |
| 247 | - //////////////rowwise transfer////////////// | 322 | + bool is_a8W4_float = x1.dtype() == at::kFloat8_e4m3fn && x2.dtype() == at::kFloat; |
| 248 | - at::Tensor processed_scale_a = scale_a; | 323 | + at::IntArrayRef group_size_list = group_sizes.value_or(at::IntArrayRef{}); |
| 249 | - at::Tensor processed_scale_b = scale_b; | 324 | + int64_t group_size = check_and_get_groups(group_size_list); |
| 250 | - if (mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn | 325 | + bool is_a4w4 = x1.dtype() == at::kInt && x2.dtype() == at::kInt; |
| 251 | - && mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn | 326 | + bool trans_x1 = is_transpose_last_two_dims(x1); |
| 252 | - && scale_a.scalar_type() == c10::ScalarType::Float | 327 | + bool trans_x2 = is_transpose_last_two_dims(x2); |
| 253 | - && scale_b.scalar_type() == c10::ScalarType::Float) { | 328 | + auto x1_dim_num = x1.dim(); |
| 254 | - if (scale_a.dim() == 2 && scale_a.sizes()[1] == 1 && scale_b.dim() == 2 && scale_b.sizes()[0] == 1) { | 329 | + auto x2_dim_num = x2.dim(); |
| 255 | - TORCH_CHECK(mat_a.stride(1) == 1, "mat_a must be contiguous in last dim"); | 330 | + auto x2_n_dim = (is_a4w4 && !trans_x2) ? x2.size(x2_dim_num - 1) * INT4_NUMS_IN_INT32 : x2.size(x2_dim_num - 1); |
| 256 | - TORCH_CHECK(mat_b.stride(0) == 1, "mat_b must be contiguous in first dim"); | ||
| 257 | - processed_scale_a = scale_a.squeeze(-1).contiguous(); | ||
| 258 | - processed_scale_b = scale_b.squeeze(0); | ||
| 259 | - } | ||
| 260 | - } | ||
| 261 | - | ||
| 262 | - //////////////parameters transfer////////////// | ||
| 263 | - at::Tensor x1 = mat_a; | ||
| 264 | - at::Tensor x2 = mat_b; | ||
| 265 | - c10::optional<at::Tensor> pertoken_scale = processed_scale_a; | ||
| 266 | - at::Tensor scale = processed_scale_b; | ||
| 267 | - c10::optional<int64_t> scale_dtype = c10::nullopt; // scale_b.scalar_type() | ||
| 268 | - | ||
| 269 | - c10::optional<int64_t> output_dtype = ToIntType(out_dtype); | ||
| 270 | - c10::optional<at::Tensor> offset = c10::nullopt; | ||
| 271 | - c10::optional<int64_t> x1_dtype = c10::nullopt; | ||
| 272 | - c10::optional<int64_t> x2_dtype = c10::nullopt; | ||
| 273 | - c10::optional<int64_t> pertoken_scale_dtype = c10::nullopt; | ||
| 274 | - c10::OptionalIntArrayRef group_sizes = c10::nullopt; | ||
| 275 | - c10::optional<at::Tensor> y_scale = c10::nullopt; | ||
| 276 | - | ||
| 277 | - | ||
| 278 | -///////////////////////////////////////////npu_quant_matmul////////////////////////////////////// | ||
| 279 | - if (is_nz_format(x2)) { | ||
| 280 | - static const bool is_quant_matmul_weight_nz_available = check_aclnn_kernel_available("aclnnQuantMatmulWeightNz"); | ||
| 281 | - TORCH_CHECK(is_quant_matmul_weight_nz_available, | ||
| 282 | - "Get aclnnQuantMatmulWeightNz or aclnnQuantMatmulWeightNzGetWorkspaceSize failed, only " | ||
| 283 | - "aclnnQuantMatmulWeightNz support X2's format is nz, please upgrade CANN.", | ||
| 284 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 285 | - } else { | ||
| 286 | - static const bool is_quant_matmul_v5_available = check_aclnn_kernel_available("aclnnQuantMatmulV5"); | ||
| 287 | - TORCH_CHECK(is_quant_matmul_v5_available, | ||
| 288 | - "Get aclnnQuantMatmulV5 or aclnnQuantMatmulV5 failed, only " | ||
| 289 | - "aclnnQuantMatmulV5 support A8W4, please upgrade CANN.", | ||
| 290 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 291 | - } | ||
| 292 | - bool is_a8W4_int = x1.dtype() == at::kChar && x2.dtype() == at::kInt; | ||
| 293 | - bool is_a8W4_float = x1.dtype() == at::kFloat8_e4m3fn && x2.dtype() == at::kFloat; | ||
| 294 | - at::IntArrayRef group_size_list = group_sizes.value_or(at::IntArrayRef{}); | ||
| 295 | - int64_t group_size = check_and_get_groups(group_size_list); | ||
| 296 | - bool is_a4w4 = x1.dtype() == at::kInt && x2.dtype() == at::kInt; | ||
| 297 | - bool trans_x1 = is_transpose_last_two_dims(x1); | ||
| 298 | - bool trans_x2 = is_transpose_last_two_dims(x2); | ||
| 299 | - auto x1_dim_num = x1.dim(); | ||
| 300 | - auto x2_dim_num = x2.dim(); | ||
| 301 | - auto x2_n_dim = (is_a4w4 && !trans_x2) ? x2.size(x2_dim_num - 1) * INT4_NUMS_IN_INT32 : x2.size(x2_dim_num - 1); | ||
| 302 | 331 | ||
| 303 | 332 | ||
| 304 | - bool mxfp4_valid = x1_dtype.has_value() && x2_dtype.has_value() && | 333 | + bool mxfp4_valid = x1_dtype.has_value() && x2_dtype.has_value() && |
| 305 | - x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) && | 334 | + x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) && |
| 306 | - x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); | 335 | + x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); |
| 307 | 336 | ||
| 308 | 337 | ||
| 309 | - bool mxfp4_valid = false; | 338 | + bool mxfp4_valid = false; |
| 310 | - if (x1_dtype.has_value()) { | 339 | + if (x1_dtype.has_value()) { |
| 311 | - mxfp4_valid = x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); | 340 | + mxfp4_valid = x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); |
| 312 | - } else { | 341 | + } else { |
| 313 | - mxfp4_valid = x1.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; | 342 | + mxfp4_valid = x1.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; |
| 314 | - } | 343 | + } |
| 315 | - if (x2_dtype.has_value()) { | 344 | + if (x2_dtype.has_value()) { |
| 316 | - mxfp4_valid = mxfp4_valid && x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); | 345 | + mxfp4_valid = mxfp4_valid && x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); |
| 317 | - } else { | 346 | + } else { |
| 318 | - mxfp4_valid = mxfp4_valid && x2.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; | 347 | + mxfp4_valid = mxfp4_valid && x2.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; |
| 319 | - } | 348 | + } |
| 320 | 349 | ||
| 321 | 350 | ||
| 322 | - c10::SmallVector<int64_t, SIZE> output_size; | 351 | + c10::SmallVector<int64_t, SIZE> output_size; |
| 323 | - if (is_a8W4_int) { | 352 | + if (is_a8W4_int) { |
| 324 | - output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; | 353 | + output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; |
| 325 | - } else if (is_a8W4_float) { | 354 | + } else if (is_a8W4_float) { |
| 326 | - if (trans_x2) { | 355 | + if (trans_x2) { |
| 327 | - output_size = {x1.sizes()[0], x2.sizes()[1]}; | 356 | + output_size = {x1.sizes()[0], x2.sizes()[1]}; |
| 328 | - } else { | ||
| 329 | - output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; | ||
| 330 | - } | ||
| 331 | } else { | 357 | } else { |
| 332 | - std::vector<uint64_t> batch_record; | 358 | + output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; |
| 333 | - uint64_t batch_val = infer_out_batch_shape(x1, x2, batch_record); | ||
| 334 | - const at::Tensor long_tensor = x1_dim_num > x2_dim_num ? x1 : x2; | ||
| 335 | - output_size = op_infer::array_to_small_vector(long_tensor.sizes()); | ||
| 336 | - if (mxfp4_valid) { | ||
| 337 | - TORCH_CHECK(x1.dim() >= 2 && x1.dim() <= 6, | ||
| 338 | - "x1 dim num should be 2 ~ 6, please check x1 dim num. Actual x1 dim = ", x1.dim(), | ||
| 339 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 340 | - TORCH_CHECK(x2.dim() >= 2 && x2.dim() <= 6, | ||
| 341 | - "x2 dim num should be 2 ~ 6, please check x2 dim num. Actual x2 dim = ", x2.dim(), | ||
| 342 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 343 | - int64_t x1_size_last_second = x1.sizes()[x1_dim_num - LAST_SECOND_DIM_INDEX]; | ||
| 344 | - int64_t x2_size_last = x2.sizes()[x2_dim_num - 1]; | ||
| 345 | - int64_t real_m = !trans_x1 ? x1_size_last_second : x1_size_last_second * FP4_IN_INT8; | ||
| 346 | - int64_t real_n = trans_x2 ? x2_size_last : x2_size_last * FP4_IN_INT8; | ||
| 347 | - output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = real_m; | ||
| 348 | - output_size[long_tensor.dim() - 1] = real_n; | ||
| 349 | - } else { | ||
| 350 | - output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = x1.size(x1_dim_num - LAST_SECOND_DIM_INDEX); | ||
| 351 | - output_size[long_tensor.dim() - 1] = x2_n_dim; | ||
| 352 | - } | ||
| 353 | - for (int64_t i = 0; i < long_tensor.dim() - LAST_SECOND_DIM_INDEX; i++) { | ||
| 354 | - output_size[i] = static_cast<int64_t>(batch_record[i]); | ||
| 355 | - } | ||
| 356 | } | 359 | } |
| 357 | - c10::TensorOptions options; | 360 | + } else { |
| 358 | - aclDataType output_acltype = ACL_INT8; | 361 | + std::vector<uint64_t> batch_record; |
| 359 | - if (!output_dtype.has_value()) { | 362 | + uint64_t batch_val = infer_out_batch_shape(x1, x2, batch_record); |
| 360 | - options = x1.options().dtype(at::kChar); | 363 | + const at::Tensor long_tensor = x1_dim_num > x2_dim_num ? x1 : x2; |
| 364 | + output_size = op_infer::array_to_small_vector(long_tensor.sizes()); | ||
| 365 | + if (mxfp4_valid) { | ||
| 366 | + TORCH_CHECK( | ||
| 367 | + x1.dim() >= 2 && x1.dim() <= 6, | ||
| 368 | + "x1 dim num should be 2 ~ 6, please check x1 dim num. Actual x1 dim = ", | ||
| 369 | + x1.dim(), | ||
| 370 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 371 | + TORCH_CHECK( | ||
| 372 | + x2.dim() >= 2 && x2.dim() <= 6, | ||
| 373 | + "x2 dim num should be 2 ~ 6, please check x2 dim num. Actual x2 dim = ", | ||
| 374 | + x2.dim(), | ||
| 375 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 376 | + int64_t x1_size_last_second = x1.sizes()[x1_dim_num - LAST_SECOND_DIM_INDEX]; | ||
| 377 | + int64_t x2_size_last = x2.sizes()[x2_dim_num - 1]; | ||
| 378 | + int64_t real_m = !trans_x1 ? x1_size_last_second : x1_size_last_second * FP4_IN_INT8; | ||
| 379 | + int64_t real_n = trans_x2 ? x2_size_last : x2_size_last * FP4_IN_INT8; | ||
| 380 | + output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = real_m; | ||
| 381 | + output_size[long_tensor.dim() - 1] = real_n; | ||
| 361 | } else { | 382 | } else { |
| 362 | - output_acltype = c10_npu::GetAclDataType(output_dtype.value()); | 383 | + output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = x1.size(x1_dim_num - LAST_SECOND_DIM_INDEX); |
| 363 | - options = x1.options().dtype(npu_preparation::convert_to_scalar_type(output_acltype)); | 384 | + output_size[long_tensor.dim() - 1] = x2_n_dim; |
| 364 | } | 385 | } |
| 365 | - at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, options); | 386 | + for (int64_t i = 0; i < long_tensor.dim() - LAST_SECOND_DIM_INDEX; i++) { |
| 387 | + output_size[i] = static_cast<int64_t>(batch_record[i]); | ||
| 388 | + } | ||
| 389 | + } | ||
| 390 | + c10::TensorOptions options; | ||
| 391 | + aclDataType output_acltype = ACL_INT8; | ||
| 392 | + if (!output_dtype.has_value()) { | ||
| 393 | + options = x1.options().dtype(at::kChar); | ||
| 394 | + } else { | ||
| 395 | + output_acltype = c10_npu::GetAclDataType(output_dtype.value()); | ||
| 396 | + options = x1.options().dtype(npu_preparation::convert_to_scalar_type(output_acltype)); | ||
| 397 | + } | ||
| 398 | + at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, options); | ||
| 366 | 399 | ||
| 367 | - const at::Tensor &offset_real = offset.value_or(at::Tensor()); | 400 | + const at::Tensor& offset_real = offset.value_or(at::Tensor()); |
| 368 | - const at::Tensor &pertoken_scale_real = pertoken_scale.value_or(at::Tensor()); | 401 | + const at::Tensor& pertoken_scale_real = pertoken_scale.value_or(at::Tensor()); |
| 369 | - const at::Tensor &bias_real = bias.value_or(at::Tensor()); | 402 | + const at::Tensor& bias_real = bias.value_or(at::Tensor()); |
| 370 | - bool transpose1 = false; | 403 | + bool transpose1 = false; |
| 371 | - bool transpose2 = false; | 404 | + bool transpose2 = false; |
| 372 | 405 | ||
| 373 | - TensorWrapper x1_wrapper = make_wrapper(x1, x1_dtype); | 406 | + TensorWrapper x1_wrapper = make_wrapper(x1, x1_dtype); |
| 374 | - TensorWrapper x2_wrapper = make_wrapper(x2, x2_dtype); | 407 | + TensorWrapper x2_wrapper = make_wrapper(x2, x2_dtype); |
| 375 | - TensorWrapper x1_scale_wrapper = make_wrapper(pertoken_scale_real, pertoken_scale_dtype); | 408 | + TensorWrapper x1_scale_wrapper = make_wrapper(pertoken_scale_real, pertoken_scale_dtype); |
| 376 | - TensorWrapper x2_scale_wrapper = make_wrapper(scale, scale_dtype); | 409 | + TensorWrapper x2_scale_wrapper = make_wrapper(scale, scale_dtype); |
| 377 | - TensorWrapper result_wrapper = make_wrapper(result, output_dtype); | 410 | + TensorWrapper result_wrapper = make_wrapper(result, output_dtype); |
| 378 | - at::Tensor x1_offset = at::empty({0}, options); | 411 | + at::Tensor x1_offset = at::empty({0}, options); |
| 379 | - at::Tensor x2_offset = at::Tensor(); | 412 | + at::Tensor x2_offset = at::Tensor(); |
| 380 | - at::Tensor y_offset = at::empty({0}, options); | 413 | + at::Tensor y_offset = at::empty({0}, options); |
| 381 | - if (is_a8W4_int) { // Only A8W4 int needs y_offset | 414 | + if (is_a8W4_int) { // Only A8W4 int needs y_offset |
| 382 | - y_offset = offset_real; | 415 | + y_offset = offset_real; |
| 416 | + } else { | ||
| 417 | + x2_offset = offset_real; | ||
| 418 | + } | ||
| 419 | + | ||
| 420 | + bool use_aclnn_v5 = | ||
| 421 | + x1_dtype.has_value() || (x1.dtype() != at::kInt && x1.dtype() != at::kChar) || is_a8W4_float || is_a8W4_int; | ||
| 422 | + | ||
| 423 | + aclDataType pertoken_scale_dtype_real = pertoken_scale_dtype.has_value() | ||
| 424 | + ? c10_npu::GetAclDataType(pertoken_scale_dtype.value()) | ||
| 425 | + : (pertoken_scale.has_value() ? c10_npu::GetAclDataType(static_cast<int64_t>(pertoken_scale_real.scalar_type())) | ||
| 426 | + : aclDataType::ACL_INT8); | ||
| 427 | + bool need_check_trans = pertoken_scale.has_value() && | ||
| 428 | + (((pertoken_scale_real.dim() == x1.dim() && scale.dim() == x2.dim()) || | ||
| 429 | + pertoken_scale_dtype_real == aclDataType::ACL_FLOAT8_E8M0) && | ||
| 430 | + (pertoken_scale_real.dim() >= 2 && scale.dim() >= 2)) && | ||
| 431 | + !(is_a8W4_float || is_a8W4_int); | ||
| 432 | + if (need_check_trans) { | ||
| 433 | + int64_t dim_x1 = x1.dim() - 2; // check the last 2 dim | ||
| 434 | + int64_t dim_x2 = x2.dim() - 2; // check the last 2 dim | ||
| 435 | + int64_t dim_x1_scale = 0; | ||
| 436 | + int64_t dim_x2_scale = 0; | ||
| 437 | + if (pertoken_scale_dtype_real != aclDataType::ACL_FLOAT8_E8M0) { | ||
| 438 | + dim_x1_scale = pertoken_scale_real.dim() - 2; // check the last 2 dim in GB/BB | ||
| 439 | + dim_x2_scale = scale.dim() - 2; // check the last 2 dim in GB/BB | ||
| 440 | + } | ||
| 441 | + TORCH_CHECK( | ||
| 442 | + is_x_scale_same_transpose(x1, pertoken_scale_real, dim_x1, dim_x1_scale), | ||
| 443 | + "Input x1 tensor and pertoken_scale tensor's transpose are not same, please check input.", | ||
| 444 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 445 | + TORCH_CHECK( | ||
| 446 | + is_x_scale_same_transpose(x2, scale, dim_x2, dim_x2_scale), | ||
| 447 | + "Input x2 tensor and scale tensor's transpose are not same, please check input.", | ||
| 448 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 449 | + } | ||
| 450 | + | ||
| 451 | + bool use_trans_quant_param = scale.dtype() == at::kFloat && !pertoken_scale.has_value() && | ||
| 452 | + (output_acltype != ACL_BF16 || use_aclnn_v5) && output_acltype != ACL_INT32; | ||
| 453 | + if (use_trans_quant_param) { | ||
| 454 | + const at::Tensor quant_param = op_api::npu_trans_quant_param(scale, offset); | ||
| 455 | + if (is_nz_format(x2)) { | ||
| 456 | + EXEC_NPU_CMD( | ||
| 457 | + aclnnQuantMatmulWeightNz, | ||
| 458 | + x1_wrapper, | ||
| 459 | + x2_wrapper, | ||
| 460 | + pertoken_scale_real, | ||
| 461 | + quant_param, | ||
| 462 | + y_scale, | ||
| 463 | + x1_offset, | ||
| 464 | + x2_offset, | ||
| 465 | + y_offset, | ||
| 466 | + bias_real, | ||
| 467 | + transpose1, | ||
| 468 | + transpose2, | ||
| 469 | + group_size, | ||
| 470 | + result_wrapper); | ||
| 383 | } else { | 471 | } else { |
| 384 | - x2_offset = offset_real; | 472 | + EXEC_NPU_CMD( |
| 473 | + aclnnQuantMatmulV5, | ||
| 474 | + x1_wrapper, | ||
| 475 | + x2_wrapper, | ||
| 476 | + pertoken_scale_real, | ||
| 477 | + quant_param, | ||
| 478 | + y_scale, | ||
| 479 | + x1_offset, | ||
| 480 | + x2_offset, | ||
| 481 | + y_offset, | ||
| 482 | + bias_real, | ||
| 483 | + transpose1, | ||
| 484 | + transpose2, | ||
| 485 | + group_size, | ||
| 486 | + result_wrapper); | ||
| 385 | } | 487 | } |
| 386 | - | 488 | + } else { |
| 387 | - bool use_aclnn_v5 = x1_dtype.has_value() || (x1.dtype() != at::kInt && x1.dtype() != at::kChar) || | 489 | + if (!is_a4w4 && is_nz_format(x2)) { |
| 388 | - is_a8W4_float || is_a8W4_int; | 490 | + EXEC_NPU_CMD( |
| 389 | - | 491 | + aclnnQuantMatmulWeightNz, |
| 390 | - aclDataType pertoken_scale_dtype_real = pertoken_scale_dtype.has_value() | 492 | + x1_wrapper, |
| 391 | - ? c10_npu::GetAclDataType(pertoken_scale_dtype.value()) | 493 | + x2_wrapper, |
| 392 | - : (pertoken_scale.has_value() | 494 | + x1_scale_wrapper, |
| 393 | - ? c10_npu::GetAclDataType(static_cast<int64_t>(pertoken_scale_real.scalar_type())) | 495 | + x2_scale_wrapper, |
| 394 | - : aclDataType::ACL_INT8); | 496 | + y_scale, |
| 395 | - bool need_check_trans = pertoken_scale.has_value() | 497 | + x1_offset, |
| 396 | - && (((pertoken_scale_real.dim() == x1.dim() && scale.dim() == x2.dim()) | 498 | + x2_offset, |
| 397 | - || pertoken_scale_dtype_real == aclDataType::ACL_FLOAT8_E8M0) | 499 | + y_offset, |
| 398 | - && (pertoken_scale_real.dim() >= 2 && scale.dim() >= 2)) | 500 | + bias_real, |
| 399 | - && !(is_a8W4_float || is_a8W4_int); | 501 | + transpose1, |
| 400 | - if (need_check_trans) { | 502 | + transpose2, |
| 401 | - int64_t dim_x1 = x1.dim() - 2; // check the last 2 dim | 503 | + group_size, |
| 402 | - int64_t dim_x2 = x2.dim() - 2; // check the last 2 dim | 504 | + result_wrapper); |
| 403 | - int64_t dim_x1_scale = 0; | ||
| 404 | - int64_t dim_x2_scale = 0; | ||
| 405 | - if (pertoken_scale_dtype_real != aclDataType::ACL_FLOAT8_E8M0) { | ||
| 406 | - dim_x1_scale = pertoken_scale_real.dim() - 2; // check the last 2 dim in GB/BB | ||
| 407 | - dim_x2_scale = scale.dim() - 2; // check the last 2 dim in GB/BB | ||
| 408 | - } | ||
| 409 | - TORCH_CHECK(is_x_scale_same_transpose(x1, pertoken_scale_real, dim_x1, dim_x1_scale), | ||
| 410 | - "Input x1 tensor and pertoken_scale tensor's transpose are not same, please check input.", | ||
| 411 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 412 | - TORCH_CHECK(is_x_scale_same_transpose(x2, scale, dim_x2, dim_x2_scale), | ||
| 413 | - "Input x2 tensor and scale tensor's transpose are not same, please check input.", | ||
| 414 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 415 | - } | ||
| 416 | - | ||
| 417 | - bool use_trans_quant_param = scale.dtype() == at::kFloat && !pertoken_scale.has_value() && | ||
| 418 | - (output_acltype != ACL_BF16 || use_aclnn_v5) && output_acltype != ACL_INT32; | ||
| 419 | - if (use_trans_quant_param) { | ||
| 420 | - const at::Tensor quant_param = op_api::npu_trans_quant_param(scale, offset); | ||
| 421 | - if (is_nz_format(x2)) { | ||
| 422 | - EXEC_NPU_CMD(aclnnQuantMatmulWeightNz, x1_wrapper, x2_wrapper, pertoken_scale_real, quant_param, y_scale, | ||
| 423 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | ||
| 424 | - } else { | ||
| 425 | - EXEC_NPU_CMD(aclnnQuantMatmulV5, x1_wrapper, x2_wrapper, pertoken_scale_real, quant_param, y_scale, | ||
| 426 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | ||
| 427 | - } | ||
| 428 | } else { | 505 | } else { |
| 429 | - if (!is_a4w4 && is_nz_format(x2)) { | 506 | + EXEC_NPU_CMD( |
| 430 | - EXEC_NPU_CMD(aclnnQuantMatmulWeightNz, x1_wrapper, x2_wrapper, x1_scale_wrapper, x2_scale_wrapper, y_scale, | 507 | + aclnnQuantMatmulV5, |
| 431 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | 508 | + x1_wrapper, |
| 432 | - } else { | 509 | + x2_wrapper, |
| 433 | - EXEC_NPU_CMD(aclnnQuantMatmulV5, x1_wrapper, x2_wrapper, x1_scale_wrapper, x2_scale_wrapper, y_scale, | 510 | + x1_scale_wrapper, |
| 434 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | 511 | + x2_scale_wrapper, |
| 435 | - } | 512 | + y_scale, |
| 513 | + x1_offset, | ||
| 514 | + x2_offset, | ||
| 515 | + y_offset, | ||
| 516 | + bias_real, | ||
| 517 | + transpose1, | ||
| 518 | + transpose2, | ||
| 519 | + group_size, | ||
| 520 | + result_wrapper); | ||
| 436 | } | 521 | } |
| 522 | + } | ||
| 437 | 523 | ||
| 438 | - return result; | 524 | + return result; |
| 439 | } | 525 | } |
| 440 | 526 | ||
| 441 | -} | 527 | +} // namespace op_api |
| @@ -24,19 +24,19 @@ | |||
| 24 | // Helper functions for ceil_div and round_up | 24 | // Helper functions for ceil_div and round_up |
| 25 | template <typename T> | 25 | template <typename T> |
| 26 | inline T ceil_div(T a, T b) { | 26 | inline T ceil_div(T a, T b) { |
| 27 | - if (b == 0) return T{}; | 27 | + if (b == 0) |
| 28 | - return (a + b - 1) / b; | 28 | + return T{}; |
| 29 | + return (a + b - 1) / b; | ||
| 29 | } | 30 | } |
| 30 | 31 | ||
| 31 | template <typename T> | 32 | template <typename T> |
| 32 | inline T round_up(T value, T alignment) { | 33 | inline T round_up(T value, T alignment) { |
| 33 | - if (alignment == 0) { | 34 | + if (alignment == 0) { |
| 34 | - return value; | 35 | + return value; |
| 35 | - } | 36 | + } |
| 36 | - return (value + alignment - 1) / alignment * alignment; | 37 | + return (value + alignment - 1) / alignment * alignment; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| 39 | - | ||
| 40 | namespace op_api { | 40 | namespace op_api { |
| 41 | constexpr size_t LAST_SECOND_DIM_INDEX = 2; | 41 | constexpr size_t LAST_SECOND_DIM_INDEX = 2; |
| 42 | constexpr int64_t PERGROUP_DIM_NUM = 2; | 42 | constexpr int64_t PERGROUP_DIM_NUM = 2; |
| @@ -46,170 +46,189 @@ static const size_t A8W4_GROUP_DIM = 3; | |||
| 46 | static const size_t A8W4_INPUT_DIM = 2; | 46 | static const size_t A8W4_INPUT_DIM = 2; |
| 47 | using npu_preparation = at_npu::native::OpPreparation; | 47 | using npu_preparation = at_npu::native::OpPreparation; |
| 48 | 48 | ||
| 49 | -bool static is_transpose_last_two_dims(const at::Tensor &tensor) | 49 | +bool static is_transpose_last_two_dims(const at::Tensor& tensor) { |
| 50 | -{ | 50 | + if (tensor.dim() < 2 || tensor.dim() > 6) { |
| 51 | - if (tensor.dim() < 2 || tensor.dim() > 6) { | 51 | + return false; |
| 52 | + } | ||
| 53 | + int64_t dim1 = tensor.dim() - 1; | ||
| 54 | + int64_t dim2 = tensor.dim() - 2; | ||
| 55 | + if (tensor.stride(dim2) == 1 && tensor.stride(dim1) == tensor.size(dim2)) { | ||
| 56 | + int64_t tmpNxD = tensor.size(dim1) * tensor.size(dim2); | ||
| 57 | + for (int64_t batchDim = tensor.dim() - 3; batchDim >= 0; batchDim--) { | ||
| 58 | + if (tensor.stride(batchDim) != tmpNxD) { | ||
| 52 | return false; | 59 | return false; |
| 60 | + } | ||
| 61 | + tmpNxD *= tensor.size(batchDim); | ||
| 53 | } | 62 | } |
| 54 | - int64_t dim1 = tensor.dim() - 1; | 63 | + if (tensor.size(dim1) == 1 && tensor.size(dim2) == 1) { |
| 55 | - int64_t dim2 = tensor.dim() - 2; | 64 | + return false; |
| 56 | - if (tensor.stride(dim2) == 1 && tensor.stride(dim1) == tensor.size(dim2)) { | ||
| 57 | - int64_t tmpNxD = tensor.size(dim1) * tensor.size(dim2); | ||
| 58 | - for (int64_t batchDim = tensor.dim() - 3; batchDim >= 0; batchDim--) { | ||
| 59 | - if (tensor.stride(batchDim) != tmpNxD) { | ||
| 60 | - return false; | ||
| 61 | - } | ||
| 62 | - tmpNxD *= tensor.size(batchDim); | ||
| 63 | - } | ||
| 64 | - if (tensor.size(dim1) == 1 && tensor.size(dim2) == 1) { | ||
| 65 | - return false; | ||
| 66 | - } | ||
| 67 | - return true; | ||
| 68 | } | 65 | } |
| 69 | - return false; | 66 | + return true; |
| 67 | + } | ||
| 68 | + return false; | ||
| 70 | } | 69 | } |
| 71 | 70 | ||
| 72 | -static bool is_transpose_certain_two_dims(const at::Tensor &tensor, int64_t dim) | 71 | +static bool is_transpose_certain_two_dims(const at::Tensor& tensor, int64_t dim) { |
| 73 | -{ | 72 | + return tensor.stride(dim + 1) == tensor.stride(dim) * tensor.size(dim); |
| 74 | - return tensor.stride(dim + 1) == tensor.stride(dim) * tensor.size(dim); | ||
| 75 | } | 73 | } |
| 76 | 74 | ||
| 77 | -static bool is_x_scale_same_transpose(const at::Tensor &x, const at::Tensor &scale, int64_t dim_x, int64_t dim_scale) | 75 | +static bool is_x_scale_same_transpose(const at::Tensor& x, const at::Tensor& scale, int64_t dim_x, int64_t dim_scale) { |
| 78 | -{ | 76 | + if (x.dim() < dim_x + 2 || scale.dim() < dim_scale + 2) { // make sure dims after the start dim are no less than 2 |
| 79 | - if (x.dim() < dim_x + 2 || scale.dim() < dim_scale + 2) { // make sure dims after the start dim are no less than 2 | 77 | + return true; |
| 80 | - return true; | 78 | + } |
| 81 | - } | 79 | + if (x.size(dim_x) == 1 && x.size(dim_x + 1) == 1) { |
| 82 | - if (x.size(dim_x) == 1 && x.size(dim_x + 1)== 1) { | 80 | + return true; |
| 83 | - return true; | 81 | + } |
| 84 | - } | 82 | + if (scale.size(dim_scale) == 1 && scale.size(dim_scale + 1) == 1) { |
| 85 | - if (scale.size(dim_scale) == 1 && scale.size(dim_scale + 1)== 1) { | 83 | + return true; |
| 86 | - return true; | 84 | + } |
| 87 | - } | 85 | + bool x_trans = is_transpose_certain_two_dims(x, dim_x); |
| 88 | - bool x_trans = is_transpose_certain_two_dims(x, dim_x); | 86 | + bool scale_trans = is_transpose_certain_two_dims(scale, dim_scale); |
| 89 | - bool scale_trans = is_transpose_certain_two_dims(scale, dim_scale); | 87 | + if (x_trans == scale_trans) { |
| 90 | - if (x_trans == scale_trans) { | 88 | + return true; |
| 91 | - return true; | 89 | + } |
| 92 | - } | 90 | + return false; |
| 93 | - return false; | ||
| 94 | } | 91 | } |
| 95 | -static bool is_nz_format(const at::Tensor& x2) | 92 | +static bool is_nz_format(const at::Tensor& x2) { |
| 96 | -{ | 93 | + const torch_npu::NPUStorageDesc& tensor_desc = torch_npu::NPUBridge::GetNpuStorageImpl(x2)->npu_desc_; |
| 97 | - const torch_npu::NPUStorageDesc &tensor_desc = | 94 | + return tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ || tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_4 || |
| 98 | - torch_npu::NPUBridge::GetNpuStorageImpl(x2)->npu_desc_; | 95 | + tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_16; |
| 99 | - return tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ || | ||
| 100 | - tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_4 || | ||
| 101 | - tensor_desc.npu_format_ == ACL_FORMAT_FRACTAL_NZ_C0_16; | ||
| 102 | } | 96 | } |
| 103 | 97 | ||
| 104 | -static uint64_t infer_out_batch_shape(const at::Tensor &x1, const at::Tensor &x2, std::vector<uint64_t> &batch_record) | 98 | +static uint64_t infer_out_batch_shape(const at::Tensor& x1, const at::Tensor& x2, std::vector<uint64_t>& batch_record) { |
| 105 | -{ | 99 | + TORCH_CHECK( |
| 106 | - TORCH_CHECK(at_npu::native::FormatHelper::IsBaseFormatType(x2) || is_nz_format(x2), | 100 | + at_npu::native::FormatHelper::IsBaseFormatType(x2) || is_nz_format(x2), |
| 107 | - "x2 should be in the original image format or nz format, but it is ", | 101 | + "x2 should be in the original image format or nz format, but it is ", |
| 108 | - npu_preparation::get_tensor_npu_format(x2), OPS_ERROR(ErrCode::PARAM)); | 102 | + npu_preparation::get_tensor_npu_format(x2), |
| 109 | - uint64_t batch_val = 1; | 103 | + OPS_ERROR(ErrCode::PARAM)); |
| 110 | - auto x1_dim_num = x1.dim(); | 104 | + uint64_t batch_val = 1; |
| 111 | - auto x2_dim_num = x2.dim(); | 105 | + auto x1_dim_num = x1.dim(); |
| 112 | - auto out_dim_num = std::max(x1_dim_num, x2_dim_num); | 106 | + auto x2_dim_num = x2.dim(); |
| 113 | - auto &shape_long = x1_dim_num > x2_dim_num ? x1 : x2; | 107 | + auto out_dim_num = std::max(x1_dim_num, x2_dim_num); |
| 114 | - auto &shape_short = x1_dim_num > x2_dim_num ? x2 : x1; | 108 | + auto& shape_long = x1_dim_num > x2_dim_num ? x1 : x2; |
| 115 | - int64_t vaild_offset = out_dim_num - std::min(x1_dim_num, x2_dim_num); | 109 | + auto& shape_short = x1_dim_num > x2_dim_num ? x2 : x1; |
| 116 | - for (int64_t i = 0; i < out_dim_num - LAST_SECOND_DIM_INDEX; i++) { | 110 | + int64_t vaild_offset = out_dim_num - std::min(x1_dim_num, x2_dim_num); |
| 117 | - auto short_dim = i < vaild_offset ? 1 : shape_short.size(i - vaild_offset); | 111 | + for (int64_t i = 0; i < out_dim_num - LAST_SECOND_DIM_INDEX; i++) { |
| 118 | - auto long_dim = shape_long.size(i); | 112 | + auto short_dim = i < vaild_offset ? 1 : shape_short.size(i - vaild_offset); |
| 119 | - TORCH_CHECK(!(short_dim > 1 && long_dim > 1 && short_dim != long_dim), | 113 | + auto long_dim = shape_long.size(i); |
| 120 | - "the x1 shape and x2 shape not supported for broadcast, the short_dim is ", | 114 | + TORCH_CHECK( |
| 121 | - short_dim, " and the long_dim is ", long_dim, OPS_ERROR(ErrCode::PARAM)); | 115 | + !(short_dim > 1 && long_dim > 1 && short_dim != long_dim), |
| 122 | - uint64_t cur_batch_value = static_cast<uint64_t>(std::max(short_dim, long_dim)); | 116 | + "the x1 shape and x2 shape not supported for broadcast, the short_dim is ", |
| 123 | - batch_val = batch_val * cur_batch_value; | 117 | + short_dim, |
| 124 | - batch_record.push_back(cur_batch_value); | 118 | + " and the long_dim is ", |
| 125 | - } | 119 | + long_dim, |
| 126 | - return batch_val; | 120 | + OPS_ERROR(ErrCode::PARAM)); |
| 121 | + uint64_t cur_batch_value = static_cast<uint64_t>(std::max(short_dim, long_dim)); | ||
| 122 | + batch_val = batch_val * cur_batch_value; | ||
| 123 | + batch_record.push_back(cur_batch_value); | ||
| 124 | + } | ||
| 125 | + return batch_val; | ||
| 127 | } | 126 | } |
| 128 | 127 | ||
| 129 | -static int64_t check_and_get_groups(at::IntArrayRef group_size_list) | 128 | +static int64_t check_and_get_groups(at::IntArrayRef group_size_list) { |
| 130 | -{ | 129 | + int64_t groups = 0; |
| 131 | - int64_t groups = 0; | 130 | + if (group_size_list.empty()) { |
| 132 | - if (group_size_list.empty()) { | ||
| 133 | - return groups; | ||
| 134 | - } | ||
| 135 | - size_t group_dim = group_size_list.size(); | ||
| 136 | - TORCH_CHECK(group_dim == A8W4_GROUP_DIM, "group_sizes only support input with three elements, but got ", | ||
| 137 | - group_dim, OPS_ERROR(ErrCode::PARAM)); | ||
| 138 | - int64_t group_m = static_cast<int64_t>(group_size_list[0]); | ||
| 139 | - int64_t group_n = static_cast<int64_t>(group_size_list[1]); | ||
| 140 | - int64_t group_k = static_cast<int64_t>(group_size_list[2]); | ||
| 141 | - bool invalid_group_param = ((group_m <= GROUP_MAX && group_m >= 0) | ||
| 142 | - && (group_n <= GROUP_MAX && group_n >= 0) | ||
| 143 | - && (group_k <= GROUP_MAX && group_k >= 0)); | ||
| 144 | - TORCH_CHECK(invalid_group_param, "group param value must conform to range [0, 65535]", OPS_ERROR(ErrCode::VALUE)); | ||
| 145 | - groups = static_cast<int64_t>((static_cast<uint64_t>(group_m) << 32) + (static_cast<uint64_t>(group_n) << 16) + | ||
| 146 | - (static_cast<uint64_t>(group_k))); | ||
| 147 | return groups; | 131 | return groups; |
| 132 | + } | ||
| 133 | + size_t group_dim = group_size_list.size(); | ||
| 134 | + TORCH_CHECK( | ||
| 135 | + group_dim == A8W4_GROUP_DIM, | ||
| 136 | + "group_sizes only support input with three elements, but got ", | ||
| 137 | + group_dim, | ||
| 138 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 139 | + int64_t group_m = static_cast<int64_t>(group_size_list[0]); | ||
| 140 | + int64_t group_n = static_cast<int64_t>(group_size_list[1]); | ||
| 141 | + int64_t group_k = static_cast<int64_t>(group_size_list[2]); | ||
| 142 | + bool invalid_group_param = | ||
| 143 | + ((group_m <= GROUP_MAX && group_m >= 0) && (group_n <= GROUP_MAX && group_n >= 0) && | ||
| 144 | + (group_k <= GROUP_MAX && group_k >= 0)); | ||
| 145 | + TORCH_CHECK(invalid_group_param, "group param value must conform to range [0, 65535]", OPS_ERROR(ErrCode::VALUE)); | ||
| 146 | + groups = static_cast<int64_t>( | ||
| 147 | + (static_cast<uint64_t>(group_m) << 32) + (static_cast<uint64_t>(group_n) << 16) + | ||
| 148 | + (static_cast<uint64_t>(group_k))); | ||
| 149 | + return groups; | ||
| 148 | } | 150 | } |
| 149 | 151 | ||
| 150 | static const std::map<c10::ScalarType, int64_t> SCALAR_TO_INT_TYPE_MAP = { | 152 | static const std::map<c10::ScalarType, int64_t> SCALAR_TO_INT_TYPE_MAP = { |
| 151 | - {c10::ScalarType::Char, static_cast<int64_t>(at::kChar)}, /**< int8 */ | 153 | + {c10::ScalarType::Char, static_cast<int64_t>(at::kChar)}, /**< int8 */ |
| 152 | - {c10::ScalarType::Int, static_cast<int64_t>(at::kInt)}, /**< int32 */ | 154 | + {c10::ScalarType::Int, static_cast<int64_t>(at::kInt)}, /**< int32 */ |
| 153 | - {c10::ScalarType::BFloat16, static_cast<int64_t>(at::kBFloat16)}, /**< bfp16 */ | 155 | + {c10::ScalarType::BFloat16, static_cast<int64_t>(at::kBFloat16)}, /**< bfp16 */ |
| 154 | - {c10::ScalarType::Half, static_cast<int64_t>(at::kHalf)}, /**< fp16 */ | 156 | + {c10::ScalarType::Half, static_cast<int64_t>(at::kHalf)}, /**< fp16 */ |
| 155 | - {c10::ScalarType::Float, static_cast<int64_t>(at::kFloat)}, /**< fp32 */ | 157 | + {c10::ScalarType::Float, static_cast<int64_t>(at::kFloat)}, /**< fp32 */ |
| 156 | 158 | ||
| 157 | - {c10::ScalarType::Float8_e4m3fn, static_cast<int64_t>(at::kFloat8_e4m3fn)}, /**< fp8e4m3 */ | 159 | + {c10::ScalarType::Float8_e4m3fn, static_cast<int64_t>(at::kFloat8_e4m3fn)}, /**< fp8e4m3 */ |
| 158 | - {c10::ScalarType::Float8_e5m2, static_cast<int64_t>(at::kFloat8_e5m2)}, /**< fp8e5m2 */ | 160 | + {c10::ScalarType::Float8_e5m2, static_cast<int64_t>(at::kFloat8_e5m2)}, /**< fp8e5m2 */ |
| 159 | - {c10::ScalarType::Byte, static_cast<int64_t>(c10_npu::DType::HIFLOAT8)} /**< hif8 */ | 161 | + {c10::ScalarType::Byte, static_cast<int64_t>(c10_npu::DType::HIFLOAT8)} /**< hif8 */ |
| 160 | }; | 162 | }; |
| 161 | 163 | ||
| 162 | -static c10::optional<int64_t> ToIntType(const std::optional<c10::ScalarType> &torchType) { | 164 | +static c10::optional<int64_t> ToIntType(const std::optional<c10::ScalarType>& torchType) { |
| 163 | - c10::optional<int64_t> int_type = c10::nullopt; | 165 | + c10::optional<int64_t> int_type = c10::nullopt; |
| 164 | - if (torchType.has_value()) { | 166 | + if (torchType.has_value()) { |
| 165 | - const auto &it = SCALAR_TO_INT_TYPE_MAP.find(torchType.value()); | 167 | + const auto& it = SCALAR_TO_INT_TYPE_MAP.find(torchType.value()); |
| 166 | - if (it != SCALAR_TO_INT_TYPE_MAP.cend()) { | 168 | + if (it != SCALAR_TO_INT_TYPE_MAP.cend()) { |
| 167 | - int_type = c10::make_optional(it->second); | 169 | + int_type = c10::make_optional(it->second); |
| 168 | - } | ||
| 169 | } | 170 | } |
| 170 | - return int_type; | 171 | + } |
| 172 | + return int_type; | ||
| 171 | } | 173 | } |
| 172 | 174 | ||
| 173 | -using acceptance_fn = std::function<bool(c10::ScalarType, std::vector<ScalingType>&, c10::ArrayRef<at::Tensor>&, c10::ScalarType, std::vector<ScalingType>&, c10::ArrayRef<at::Tensor>&)>; | 175 | +using acceptance_fn = std::function<bool( |
| 176 | + c10::ScalarType, | ||
| 177 | + std::vector<ScalingType>&, | ||
| 178 | + c10::ArrayRef<at::Tensor>&, | ||
| 179 | + c10::ScalarType, | ||
| 180 | + std::vector<ScalingType>&, | ||
| 181 | + c10::ArrayRef<at::Tensor>&)>; | ||
| 174 | 182 | ||
| 175 | // Namespace for scaled_blas check functions | 183 | // Namespace for scaled_blas check functions |
| 176 | namespace scaled_blas { | 184 | namespace scaled_blas { |
| 177 | 185 | ||
| 178 | // Check deepseek recipe (BlockWise 1x128 and 128x128 scaling) | 186 | // Check deepseek recipe (BlockWise 1x128 and 128x128 scaling) |
| 179 | -bool check_deepseek_recipe(c10::ScalarType a_type, std::vector<ScalingType>& a_recipe, c10::ArrayRef<at::Tensor>& a_scale, | 187 | +bool check_deepseek_recipe( |
| 180 | - c10::ScalarType b_type, std::vector<ScalingType>& b_recipe, c10::ArrayRef<at::Tensor>& b_scale, | 188 | + c10::ScalarType a_type, |
| 181 | - ScalingType expected_a_type, ScalingType expected_b_type) { | 189 | + std::vector<ScalingType>& a_recipe, |
| 182 | - if (a_type != c10::ScalarType::Float8_e4m3fn && a_type != c10::ScalarType::Float8_e5m2) { | 190 | + c10::ArrayRef<at::Tensor>& a_scale, |
| 183 | - return false; | 191 | + c10::ScalarType b_type, |
| 184 | - } | 192 | + std::vector<ScalingType>& b_recipe, |
| 185 | - if (b_type != c10::ScalarType::Float8_e4m3fn && b_type != c10::ScalarType::Float8_e5m2) { | 193 | + c10::ArrayRef<at::Tensor>& b_scale, |
| 186 | - return false; | 194 | + ScalingType expected_a_type, |
| 187 | - } | 195 | + ScalingType expected_b_type) { |
| 188 | - if (a_recipe.empty() || b_recipe.empty()) { | 196 | + if (a_type != c10::ScalarType::Float8_e4m3fn && a_type != c10::ScalarType::Float8_e5m2) { |
| 189 | - return false; | 197 | + return false; |
| 190 | - } | 198 | + } |
| 191 | - if (a_scale.empty() || b_scale.empty()) { | 199 | + if (b_type != c10::ScalarType::Float8_e4m3fn && b_type != c10::ScalarType::Float8_e5m2) { |
| 192 | - return false; | 200 | + return false; |
| 193 | - } | 201 | + } |
| 194 | - return (a_recipe[0] == expected_a_type && b_recipe[0] == expected_b_type); | 202 | + if (a_recipe.empty() || b_recipe.empty()) { |
| 203 | + return false; | ||
| 204 | + } | ||
| 205 | + if (a_scale.empty() || b_scale.empty()) { | ||
| 206 | + return false; | ||
| 207 | + } | ||
| 208 | + return (a_recipe[0] == expected_a_type && b_recipe[0] == expected_b_type); | ||
| 195 | } | 209 | } |
| 196 | 210 | ||
| 197 | // Check mxfp8 recipe | 211 | // Check mxfp8 recipe |
| 198 | -static bool check_mxfp8_recipe(c10::ScalarType a_type, std::vector<ScalingType>& a_recipe, c10::ArrayRef<at::Tensor>& a_scale, | 212 | +static bool check_mxfp8_recipe( |
| 199 | - c10::ScalarType b_type, std::vector<ScalingType>& b_recipe, c10::ArrayRef<at::Tensor>& b_scale) { | 213 | + c10::ScalarType a_type, |
| 200 | - if (a_type != c10::ScalarType::Float8_e4m3fn && a_type != c10::ScalarType::Float8_e5m2) { | 214 | + std::vector<ScalingType>& a_recipe, |
| 201 | - return false; | 215 | + c10::ArrayRef<at::Tensor>& a_scale, |
| 202 | - } | 216 | + c10::ScalarType b_type, |
| 203 | - if (b_type != c10::ScalarType::Float8_e4m3fn && b_type != c10::ScalarType::Float8_e5m2) { | 217 | + std::vector<ScalingType>& b_recipe, |
| 204 | - return false; | 218 | + c10::ArrayRef<at::Tensor>& b_scale) { |
| 205 | - } | 219 | + if (a_type != c10::ScalarType::Float8_e4m3fn && a_type != c10::ScalarType::Float8_e5m2) { |
| 206 | - if (a_recipe.empty() || b_recipe.empty()) { | 220 | + return false; |
| 207 | - return false; | 221 | + } |
| 208 | - } | 222 | + if (b_type != c10::ScalarType::Float8_e4m3fn && b_type != c10::ScalarType::Float8_e5m2) { |
| 209 | - if (a_scale.empty() || b_scale.empty()) { | 223 | + return false; |
| 210 | - return false; | 224 | + } |
| 211 | - } | 225 | + if (a_recipe.empty() || b_recipe.empty()) { |
| 212 | - return true; | 226 | + return false; |
| 227 | + } | ||
| 228 | + if (a_scale.empty() || b_scale.empty()) { | ||
| 229 | + return false; | ||
| 230 | + } | ||
| 231 | + return true; | ||
| 213 | } | 232 | } |
| 214 | 233 | ||
| 215 | // Check tensorwise recipe | 234 | // Check tensorwise recipe |
| @@ -233,10 +252,14 @@ bool check_tensorwise_recipe( | |||
| 233 | return false; | 252 | return false; |
| 234 | } | 253 | } |
| 235 | // Need {Tensorwise, e8m0} for A & B | 254 | // Need {Tensorwise, e8m0} for A & B |
| 236 | - if (recipe_a[0] != ScalingType::TensorWise) return false; | 255 | + if (recipe_a[0] != ScalingType::TensorWise) |
| 237 | - if (scales_a[0].scalar_type() != c10::ScalarType::Float) return false; | 256 | + return false; |
| 238 | - if (recipe_b[0] != ScalingType::TensorWise) return false; | 257 | + if (scales_a[0].scalar_type() != c10::ScalarType::Float) |
| 239 | - if (scales_b[0].scalar_type() != c10::ScalarType::Float) return false; | 258 | + return false; |
| 259 | + if (recipe_b[0] != ScalingType::TensorWise) | ||
| 260 | + return false; | ||
| 261 | + if (scales_b[0].scalar_type() != c10::ScalarType::Float) | ||
| 262 | + return false; | ||
| 240 | 263 | ||
| 241 | return true; | 264 | return true; |
| 242 | } | 265 | } |
| @@ -263,10 +286,14 @@ static bool check_rowwise_recipe( | |||
| 263 | } | 286 | } |
| 264 | 287 | ||
| 265 | // Need {RowWise, fp32} for A & B | 288 | // Need {RowWise, fp32} for A & B |
| 266 | - if (recipe_a[0] != ScalingType::RowWise) return false; | 289 | + if (recipe_a[0] != ScalingType::RowWise) |
| 267 | - if (scales_a[0].scalar_type() != c10::ScalarType::Float) return false; | 290 | + return false; |
| 268 | - if (recipe_b[0] != ScalingType::RowWise) return false; | 291 | + if (scales_a[0].scalar_type() != c10::ScalarType::Float) |
| 269 | - if (scales_b[0].scalar_type() != c10::ScalarType::Float) return false; | 292 | + return false; |
| 293 | + if (recipe_b[0] != ScalingType::RowWise) | ||
| 294 | + return false; | ||
| 295 | + if (scales_b[0].scalar_type() != c10::ScalarType::Float) | ||
| 296 | + return false; | ||
| 270 | 297 | ||
| 271 | return true; | 298 | return true; |
| 272 | } | 299 | } |
| @@ -274,37 +301,34 @@ static bool check_rowwise_recipe( | |||
| 274 | } // namespace scaled_blas | 301 | } // namespace scaled_blas |
| 275 | 302 | ||
| 276 | // Wrapper for check_deepseek_recipe that captures expected ScalingTypes | 303 | // Wrapper for check_deepseek_recipe that captures expected ScalingTypes |
| 277 | -std::function<bool(c10::ScalarType, std::vector<ScalingType>&, c10::ArrayRef<at::Tensor>&, c10::ScalarType, std::vector<ScalingType>&, c10::ArrayRef<at::Tensor>&)> | 304 | +std::function<bool( |
| 305 | + c10::ScalarType, | ||
| 306 | + std::vector<ScalingType>&, | ||
| 307 | + c10::ArrayRef<at::Tensor>&, | ||
| 308 | + c10::ScalarType, | ||
| 309 | + std::vector<ScalingType>&, | ||
| 310 | + c10::ArrayRef<at::Tensor>&)> | ||
| 278 | make_deepseek_checker(ScalingType expected_a, ScalingType expected_b) { | 311 | make_deepseek_checker(ScalingType expected_a, ScalingType expected_b) { |
| 279 | - return [expected_a, expected_b](c10::ScalarType a_type, std::vector<ScalingType>& a_recipe, c10::ArrayRef<at::Tensor>& a_scale, | 312 | + return [expected_a, expected_b]( |
| 280 | - c10::ScalarType b_type, std::vector<ScalingType>& b_recipe, c10::ArrayRef<at::Tensor>& b_scale) { | 313 | + c10::ScalarType a_type, |
| 281 | - return scaled_blas::check_deepseek_recipe(a_type, a_recipe, a_scale, b_type, b_recipe, b_scale, expected_a, expected_b); | 314 | + std::vector<ScalingType>& a_recipe, |
| 282 | - }; | 315 | + c10::ArrayRef<at::Tensor>& a_scale, |
| 316 | + c10::ScalarType b_type, | ||
| 317 | + std::vector<ScalingType>& b_recipe, | ||
| 318 | + c10::ArrayRef<at::Tensor>& b_scale) { | ||
| 319 | + return scaled_blas::check_deepseek_recipe( | ||
| 320 | + a_type, a_recipe, a_scale, b_type, b_recipe, b_scale, expected_a, expected_b); | ||
| 321 | + }; | ||
| 283 | } | 322 | } |
| 284 | 323 | ||
| 285 | using KernelDispatchItem = std::tuple<std::string, acceptance_fn, ScaledGemmImplementation>; | 324 | using KernelDispatchItem = std::tuple<std::string, acceptance_fn, ScaledGemmImplementation>; |
| 286 | -const std::array<KernelDispatchItem, 4> scale_kernel_dispatch_table = {{ | 325 | +const std::array<KernelDispatchItem, 4> scale_kernel_dispatch_table = { |
| 287 | - { | 326 | + {{"tensorwise_tensorwise", scaled_blas::check_tensorwise_recipe, ScaledGemmImplementation::TENSORWISE_TENSORWISE}, |
| 288 | - "tensorwise_tensorwise", | 327 | + {"rowwise_rowwise", scaled_blas::check_rowwise_recipe, ScaledGemmImplementation::ROWWISE_ROWWISE}, |
| 289 | - scaled_blas::check_tensorwise_recipe, | 328 | + {"deepseek_block_1x128_1x128", |
| 290 | - ScaledGemmImplementation::TENSORWISE_TENSORWISE | 329 | + make_deepseek_checker(ScalingType::BlockWise1x128, ScalingType::BlockWise1x128), |
| 291 | - }, | 330 | + ScaledGemmImplementation::BLOCK_1x128_1x128}, |
| 292 | - { | 331 | + {"mxfp8_double_channel", scaled_blas::check_mxfp8_recipe, ScaledGemmImplementation::MXFP8_MXFP8}}}; |
| 293 | - "rowwise_rowwise", | ||
| 294 | - scaled_blas::check_rowwise_recipe, | ||
| 295 | - ScaledGemmImplementation::ROWWISE_ROWWISE | ||
| 296 | - }, | ||
| 297 | - { | ||
| 298 | - "deepseek_block_1x128_1x128", | ||
| 299 | - make_deepseek_checker(ScalingType::BlockWise1x128, ScalingType::BlockWise1x128), | ||
| 300 | - ScaledGemmImplementation::BLOCK_1x128_1x128 | ||
| 301 | - }, | ||
| 302 | - { | ||
| 303 | - "mxfp8_double_channel", | ||
| 304 | - scaled_blas::check_mxfp8_recipe, | ||
| 305 | - ScaledGemmImplementation::MXFP8_MXFP8 | ||
| 306 | - } | ||
| 307 | -}}; | ||
| 308 | 332 | ||
| 309 | // Signature note: scale_a / scale_b use at::ITensorListRef so this impl matches | 333 | // Signature note: scale_a / scale_b use at::ITensorListRef so this impl matches |
| 310 | // the wrapper generated by torch_npu's codegen on PyTorch >= 2.14, where | 334 | // the wrapper generated by torch_npu's codegen on PyTorch >= 2.14, where |
| @@ -313,7 +337,9 @@ const std::array<KernelDispatchItem, 4> scale_kernel_dispatch_table = {{ | |||
| 313 | // const at::ITensorListRef&. IListRef is implicitly constructible from | 337 | // const at::ITensorListRef&. IListRef is implicitly constructible from |
| 314 | // ArrayRef, so on 2.13 the wrapper still passes at::TensorList and it converts | 338 | // ArrayRef, so on 2.13 the wrapper still passes at::TensorList and it converts |
| 315 | // transparently -- no version gating needed. See docs/issue_scaled_mm_v2_structured.md. | 339 | // transparently -- no version gating needed. See docs/issue_scaled_mm_v2_structured.md. |
| 316 | -at::Tensor _scaled_mm_v2(const at::Tensor& mat_a, const at::Tensor& mat_b, | 340 | +at::Tensor _scaled_mm_v2( |
| 341 | + const at::Tensor& mat_a, | ||
| 342 | + const at::Tensor& mat_b, | ||
| 317 | const at::ITensorListRef& scale_a_ilist, | 343 | const at::ITensorListRef& scale_a_ilist, |
| 318 | at::IntArrayRef scale_recipe_a, | 344 | at::IntArrayRef scale_recipe_a, |
| 319 | at::IntArrayRef swizzle_a, | 345 | at::IntArrayRef swizzle_a, |
| @@ -323,361 +349,478 @@ at::Tensor _scaled_mm_v2(const at::Tensor& mat_a, const at::Tensor& mat_b, | |||
| 323 | const std::optional<at::Tensor>& bias, | 349 | const std::optional<at::Tensor>& bias, |
| 324 | const std::optional<c10::ScalarType> out_dtype, // 当前cpp中不支持float8 | 350 | const std::optional<c10::ScalarType> out_dtype, // 当前cpp中不支持float8 |
| 325 | at::IntArrayRef contraction_dim, | 351 | at::IntArrayRef contraction_dim, |
| 326 | - bool use_fast_accum) | 352 | + bool use_fast_accum) { |
| 327 | -{ | 353 | + // Materialize the ilist inputs into local TensorList (ArrayRef<Tensor>) |
| 328 | - // Materialize the ilist inputs into local TensorList (ArrayRef<Tensor>) | 354 | + // views so the rest of the function body -- which does .empty() / .size() |
| 329 | - // views so the rest of the function body -- which does .empty() / .size() | 355 | + // and scale_a[i] indexing -- needs no further change. Cost: shallow |
| 330 | - // and scale_a[i] indexing -- needs no further change. Cost: shallow | 356 | + // per-Tensor refcount bump into a local vector; vector stays alive for |
| 331 | - // per-Tensor refcount bump into a local vector; vector stays alive for | 357 | + // the whole call, so the ArrayRef view never dangles. |
| 332 | - // the whole call, so the ArrayRef view never dangles. | 358 | + auto scale_a_materialized = scale_a_ilist.materialize(); |
| 333 | - auto scale_a_materialized = scale_a_ilist.materialize(); | 359 | + auto scale_b_materialized = scale_b_ilist.materialize(); |
| 334 | - auto scale_b_materialized = scale_b_ilist.materialize(); | 360 | + std::vector<at::Tensor> scale_a_owned(scale_a_materialized.begin(), scale_a_materialized.end()); |
| 335 | - std::vector<at::Tensor> scale_a_owned(scale_a_materialized.begin(), scale_a_materialized.end()); | 361 | + std::vector<at::Tensor> scale_b_owned(scale_b_materialized.begin(), scale_b_materialized.end()); |
| 336 | - std::vector<at::Tensor> scale_b_owned(scale_b_materialized.begin(), scale_b_materialized.end()); | 362 | + at::TensorList scale_a(scale_a_owned); |
| 337 | - at::TensorList scale_a(scale_a_owned); | 363 | + at::TensorList scale_b(scale_b_owned); |
| 338 | - at::TensorList scale_b(scale_b_owned); | ||
| 339 | 364 | ||
| 340 | - // check A5 | 365 | + // check A5 |
| 341 | - TORCH_CHECK(c10_npu::GetSocVersion() >= c10_npu::SocVersion::Ascend950, | 366 | + TORCH_CHECK( |
| 342 | - "_scaled_mm is supported only on the Ascend950 platform and after.", OPS_ERROR(ErrCode::PARAM)); | 367 | + c10_npu::GetSocVersion() >= c10_npu::SocVersion::Ascend950, |
| 368 | + "_scaled_mm is supported only on the Ascend950 platform and after.", | ||
| 369 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 343 | 370 | ||
| 344 | - // Check data types: mat_a and mat_b must be float8 type | 371 | + // Check data types: mat_a and mat_b must be float8 type |
| 345 | - TORCH_CHECK(mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn || | 372 | + TORCH_CHECK( |
| 346 | - mat_a.scalar_type() == c10::ScalarType::Float8_e5m2, | 373 | + mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn || mat_a.scalar_type() == c10::ScalarType::Float8_e5m2, |
| 347 | - "mat_a must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", mat_a.scalar_type(), | 374 | + "mat_a must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", |
| 348 | - OPS_ERROR(ErrCode::TYPE)); | 375 | + mat_a.scalar_type(), |
| 349 | - TORCH_CHECK(mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn || | 376 | + OPS_ERROR(ErrCode::TYPE)); |
| 350 | - mat_b.scalar_type() == c10::ScalarType::Float8_e5m2, | 377 | + TORCH_CHECK( |
| 351 | - "mat_b must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", mat_b.scalar_type(), | 378 | + mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn || mat_b.scalar_type() == c10::ScalarType::Float8_e5m2, |
| 352 | - OPS_ERROR(ErrCode::TYPE)); | 379 | + "mat_b must be float8 type (Float8_e4m3fn or Float8_e5m2), but got ", |
| 380 | + mat_b.scalar_type(), | ||
| 381 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 353 | 382 | ||
| 354 | - // Check multiplication of two Float8_e5m2 is not supported (reference: _scaled_mm_out_cuda) | 383 | + // Check multiplication of two Float8_e5m2 is not supported (reference: _scaled_mm_out_cuda) |
| 355 | - TORCH_CHECK(mat_a.scalar_type() != c10::ScalarType::Float8_e5m2 || | 384 | + TORCH_CHECK( |
| 356 | - mat_b.scalar_type() != c10::ScalarType::Float8_e5m2, | 385 | + mat_a.scalar_type() != c10::ScalarType::Float8_e5m2 || mat_b.scalar_type() != c10::ScalarType::Float8_e5m2, |
| 357 | - "Multiplication of two Float8_e5m2 matrices is not supported", | 386 | + "Multiplication of two Float8_e5m2 matrices is not supported", |
| 358 | - OPS_ERROR(ErrCode::TYPE)); | 387 | + OPS_ERROR(ErrCode::TYPE)); |
| 359 | 388 | ||
| 360 | - // Check sizes | 389 | + // Check sizes |
| 361 | - TORCH_CHECK(mat_a.dim() == 2, "mat_a must be a matrix, please check mat_a dim num." ,OPS_ERROR(ErrCode::PARAM)); | 390 | + TORCH_CHECK(mat_a.dim() == 2, "mat_a must be a matrix, please check mat_a dim num.", OPS_ERROR(ErrCode::PARAM)); |
| 362 | - TORCH_CHECK(mat_b.dim() == 2, "mat_b must be a matrix, please check mat_b dim num." ,OPS_ERROR(ErrCode::PARAM)); | 391 | + TORCH_CHECK(mat_b.dim() == 2, "mat_b must be a matrix, please check mat_b dim num.", OPS_ERROR(ErrCode::PARAM)); |
| 363 | - TORCH_CHECK(mat_a.sizes()[1] == mat_b.sizes()[0], "mat_a and mat_b shapes cannot be multiplied (",mat_a.sizes()[0], | 392 | + TORCH_CHECK( |
| 364 | - "x", mat_b.sizes()[1], " and ", mat_b.sizes()[0], "x", mat_b.sizes()[1], ")", OPS_ERROR(ErrCode::PARAM)); | 393 | + mat_a.sizes()[1] == mat_b.sizes()[0], |
| 394 | + "mat_a and mat_b shapes cannot be multiplied (", | ||
| 395 | + mat_a.sizes()[0], | ||
| 396 | + "x", | ||
| 397 | + mat_b.sizes()[1], | ||
| 398 | + " and ", | ||
| 399 | + mat_b.sizes()[0], | ||
| 400 | + "x", | ||
| 401 | + mat_b.sizes()[1], | ||
| 402 | + ")", | ||
| 403 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 365 | 404 | ||
| 366 | - // Check data types: scale_a and scale_b must be float32 or float8_e8m0 type | 405 | + // Check data types: scale_a and scale_b must be float32 or float8_e8m0 type |
| 367 | - // Check scale_a and scale_b are not empty | 406 | + // Check scale_a and scale_b are not empty |
| 368 | - TORCH_CHECK(!scale_a.empty(), "scale_a must not be empty", OPS_ERROR(ErrCode::PARAM)); | 407 | + TORCH_CHECK(!scale_a.empty(), "scale_a must not be empty", OPS_ERROR(ErrCode::PARAM)); |
| 369 | - TORCH_CHECK(!scale_b.empty(), "scale_b must not be empty", OPS_ERROR(ErrCode::PARAM)); | 408 | + TORCH_CHECK(!scale_b.empty(), "scale_b must not be empty", OPS_ERROR(ErrCode::PARAM)); |
| 370 | 409 | ||
| 371 | - TORCH_CHECK(scale_a[0].scalar_type() == c10::ScalarType::Float || | 410 | + TORCH_CHECK( |
| 372 | - scale_a[0].scalar_type() == npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), | 411 | + scale_a[0].scalar_type() == c10::ScalarType::Float || |
| 373 | - "scale_a must be float32 or float8_e8m0 type, but got ", scale_a[0].scalar_type(), | 412 | + scale_a[0].scalar_type() == |
| 374 | - OPS_ERROR(ErrCode::TYPE)); | 413 | + npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), |
| 375 | - TORCH_CHECK(scale_b[0].scalar_type() == c10::ScalarType::Float || | 414 | + "scale_a must be float32 or float8_e8m0 type, but got ", |
| 376 | - scale_b[0].scalar_type() == npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), | 415 | + scale_a[0].scalar_type(), |
| 377 | - "scale_b must be float32 or float8_e8m0 type, but got ", scale_b[0].scalar_type(), | 416 | + OPS_ERROR(ErrCode::TYPE)); |
| 378 | - OPS_ERROR(ErrCode::TYPE)); | 417 | + TORCH_CHECK( |
| 418 | + scale_b[0].scalar_type() == c10::ScalarType::Float || | ||
| 419 | + scale_b[0].scalar_type() == | ||
| 420 | + npu_preparation::convert_to_scalar_type(c10_npu::GetAclDataType(c10_npu::DType::FLOAT8_E8M0)), | ||
| 421 | + "scale_b must be float32 or float8_e8m0 type, but got ", | ||
| 422 | + scale_b[0].scalar_type(), | ||
| 423 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 379 | 424 | ||
| 380 | - // Cast integer type IDs to corresponding enumeration values | 425 | + // Cast integer type IDs to corresponding enumeration values |
| 381 | - auto scaling_type_a = convert_int_to_enum<ScalingType>(scale_recipe_a); | 426 | + auto scaling_type_a = convert_int_to_enum<ScalingType>(scale_recipe_a); |
| 382 | - auto scaling_type_b = convert_int_to_enum<ScalingType>(scale_recipe_b); | 427 | + auto scaling_type_b = convert_int_to_enum<ScalingType>(scale_recipe_b); |
| 383 | 428 | ||
| 384 | - bool matched_valid_impl = false; | 429 | + bool matched_valid_impl = false; |
| 385 | - ScaledGemmImplementation selected_kernel = ScaledGemmImplementation::NONE; | 430 | + ScaledGemmImplementation selected_kernel = ScaledGemmImplementation::NONE; |
| 386 | 431 | ||
| 387 | - // Iterate registered kernel implementations to find matching one | 432 | + // Iterate registered kernel implementations to find matching one |
| 388 | - for (const auto& entry : scale_kernel_dispatch_table) { | 433 | + for (const auto& entry : scale_kernel_dispatch_table) { |
| 389 | - auto const& kernel_id = std::get<0>(entry); | 434 | + auto const& kernel_id = std::get<0>(entry); |
| 390 | - auto const& matcher_fn = std::get<1>(entry); | 435 | + auto const& matcher_fn = std::get<1>(entry); |
| 391 | - auto const& kernel_impl = std::get<2>(entry); | 436 | + auto const& kernel_impl = std::get<2>(entry); |
| 392 | 437 | ||
| 393 | - bool config_ok = matcher_fn( | 438 | + bool config_ok = |
| 394 | - mat_a.scalar_type(), | 439 | + matcher_fn(mat_a.scalar_type(), scaling_type_a, scale_a, mat_b.scalar_type(), scaling_type_b, scale_b); |
| 395 | - scaling_type_a, | ||
| 396 | - scale_a, | ||
| 397 | - mat_b.scalar_type(), | ||
| 398 | - scaling_type_b, | ||
| 399 | - scale_b | ||
| 400 | - ); | ||
| 401 | 440 | ||
| 402 | - if (config_ok) { | 441 | + if (config_ok) { |
| 403 | - selected_kernel = kernel_impl; | 442 | + selected_kernel = kernel_impl; |
| 404 | - matched_valid_impl = true; | 443 | + matched_valid_impl = true; |
| 405 | - break; | 444 | + break; |
| 406 | - } | ||
| 407 | } | 445 | } |
| 446 | + } | ||
| 447 | + | ||
| 448 | + TORCH_CHECK( | ||
| 449 | + matched_valid_impl, | ||
| 450 | + "Unsupported scaling configuration.\n" | ||
| 451 | + "- TensorWise: mat_a/mat_b must be float8; scales float32; scale_a and scale_b are singletons (scalar).\n" | ||
| 452 | + "- RowWise: mat_a/mat_b float8; scales float32; scale_a shape (", | ||
| 453 | + mat_a.size(0), | ||
| 454 | + ", 1); scale_b shape (1, ", | ||
| 455 | + mat_b.size(1), | ||
| 456 | + "); both contiguous.\n" | ||
| 457 | + "- BlockWise 1x128: mat_a/mat_b must be float8; scales float32; scale_a shape (", | ||
| 458 | + mat_a.size(0), | ||
| 459 | + ", ", | ||
| 460 | + ceil_div<int64_t>(mat_a.size(1), 128), | ||
| 461 | + "); scale_b shape (", | ||
| 462 | + ceil_div<int64_t>(mat_b.size(0), 128), | ||
| 463 | + ", ", | ||
| 464 | + mat_b.size(1), | ||
| 465 | + "); outer-dim-major.\n" | ||
| 466 | + "- Blockwise 1x32: mat_a/mat_b float8; scales float8_e8m0fnu; scale_a elements=", | ||
| 467 | + round_up<int64_t>(mat_a.size(0), 128) * round_up<int64_t>(ceil_div<int64_t>(mat_a.size(1), 32), 4), | ||
| 468 | + "; scale_b elements=", | ||
| 469 | + round_up<int64_t>(mat_b.size(1), 128) * round_up<int64_t>(ceil_div<int64_t>(mat_b.size(0), 32), 4), | ||
| 470 | + "; contiguous only.\n" | ||
| 471 | + "Current inputs: mat_a.dtype=", | ||
| 472 | + mat_a.scalar_type(), | ||
| 473 | + ", scale_a.dtype=", | ||
| 474 | + scale_a[0].scalar_type(), | ||
| 475 | + ", scale_a.shape=", | ||
| 476 | + scale_a[0].sizes(), | ||
| 477 | + ", mat_b.dtype=", | ||
| 478 | + mat_b.scalar_type(), | ||
| 479 | + ", scale_b.dtype=", | ||
| 480 | + scale_b[0].scalar_type(), | ||
| 481 | + ", scale_b.shape=", | ||
| 482 | + scale_b[0].sizes()); | ||
| 483 | + | ||
| 484 | + // Check bias (reference: _scaled_mm_out_cuda) | ||
| 485 | + if (bias.has_value()) { | ||
| 486 | + TORCH_CHECK( | ||
| 487 | + bias->numel() == mat_b.sizes()[1], | ||
| 488 | + "Bias must be size ", | ||
| 489 | + mat_b.sizes()[1], | ||
| 490 | + " but got ", | ||
| 491 | + bias->numel(), | ||
| 492 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 493 | + // Check out_dtype vs bias compatibility | ||
| 494 | + auto out_dtype_value = out_dtype.value_or(c10::ScalarType::BFloat16); | ||
| 495 | + TORCH_CHECK( | ||
| 496 | + out_dtype_value != c10::ScalarType::Float, | ||
| 497 | + "Bias is not supported when out_dtype is set to Float32", | ||
| 498 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 499 | + TORCH_CHECK( | ||
| 500 | + bias->scalar_type() == c10::ScalarType::BFloat16 || bias->scalar_type() == c10::ScalarType::Half, | ||
| 501 | + "Bias must be BFloat16 or Half, but got ", | ||
| 502 | + bias->scalar_type(), | ||
| 503 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 504 | + TORCH_CHECK( | ||
| 505 | + (out_dtype_value != c10::ScalarType::Float && out_dtype_value != c10::ScalarType::BFloat16) || | ||
| 506 | + bias->scalar_type() == c10::ScalarType::BFloat16, | ||
| 507 | + "Bias must be BFloat16 to compute ", | ||
| 508 | + out_dtype_value, | ||
| 509 | + " output, but got ", | ||
| 510 | + bias->scalar_type(), | ||
| 511 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 512 | + TORCH_CHECK( | ||
| 513 | + out_dtype_value != c10::ScalarType::Half || bias->scalar_type() == c10::ScalarType::Half, | ||
| 514 | + "Bias must be Float16 to compute ", | ||
| 515 | + out_dtype_value, | ||
| 516 | + " output, but got ", | ||
| 517 | + bias->scalar_type(), | ||
| 518 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 519 | + } | ||
| 520 | + | ||
| 521 | + // Check out_dtype: currently only supports Float32, BFloat16, and Float16 | ||
| 522 | + if (out_dtype.has_value()) { | ||
| 523 | + TORCH_CHECK( | ||
| 524 | + out_dtype.value() == c10::ScalarType::Float || out_dtype.value() == c10::ScalarType::BFloat16 || | ||
| 525 | + out_dtype.value() == c10::ScalarType::Half, | ||
| 526 | + "out_dtype must be Float32, BFloat16, or Float16, but got ", | ||
| 527 | + out_dtype.value(), | ||
| 528 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 529 | + } | ||
| 530 | + | ||
| 531 | + bool has_contraction = !contraction_dim.empty(); | ||
| 532 | + if (has_contraction) { | ||
| 533 | + int64_t c_dim_size = static_cast<int64_t>(contraction_dim.size()); | ||
| 534 | + TORCH_CHECK(c_dim_size == 2, "contraction_dim must have exactly 2 elements", OPS_ERROR(ErrCode::PARAM)); | ||
| 535 | + | ||
| 536 | + int64_t a_contract_idx = contraction_dim[0]; | ||
| 537 | + int64_t b_contract_idx = contraction_dim[1]; | ||
| 538 | + int64_t a_dim_size = mat_a.size(a_contract_idx); | ||
| 539 | + int64_t b_dim_size = mat_b.size(b_contract_idx); | ||
| 408 | 540 | ||
| 409 | TORCH_CHECK( | 541 | TORCH_CHECK( |
| 410 | - matched_valid_impl, | 542 | + a_dim_size == b_dim_size, |
| 411 | - "Unsupported scaling configuration.\n" | 543 | + "dimension mismatch for matrix multiplication (", |
| 412 | - "- TensorWise: mat_a/mat_b must be float8; scales float32; scale_a and scale_b are singletons (scalar).\n" | 544 | + "A shape=", |
| 413 | - "- RowWise: mat_a/mat_b float8; scales float32; scale_a shape (", mat_a.size(0), ", 1); scale_b shape (1, ", mat_b.size(1), "); both contiguous.\n" | 545 | + mat_a.size(0), |
| 414 | - "- BlockWise 1x128: mat_a/mat_b must be float8; scales float32; scale_a shape (", mat_a.size(0), ", ", ceil_div<int64_t>(mat_a.size(1), 128), "); scale_b shape (", ceil_div<int64_t>(mat_b.size(0), 128), ", ", mat_b.size(1), "); outer-dim-major.\n" | 546 | + "x", |
| 415 | - "- Blockwise 1x32: mat_a/mat_b float8; scales float8_e8m0fnu; scale_a elements=", round_up<int64_t>(mat_a.size(0), 128) * round_up<int64_t>(ceil_div<int64_t>(mat_a.size(1), 32), 4), "; scale_b elements=", round_up<int64_t>(mat_b.size(1), 128) * round_up<int64_t>(ceil_div<int64_t>(mat_b.size(0), 32), 4), "; contiguous only.\n" | 547 | + mat_a.size(1), |
| 416 | - "Current inputs: mat_a.dtype=", mat_a.scalar_type(), ", scale_a.dtype=", scale_a[0].scalar_type(), ", scale_a.shape=", scale_a[0].sizes(), | 548 | + ", B shape=", |
| 417 | - ", mat_b.dtype=", mat_b.scalar_type(), ", scale_b.dtype=", scale_b[0].scalar_type(), ", scale_b.shape=", scale_b[0].sizes() | 549 | + mat_b.size(0), |
| 418 | - ); | 550 | + "x", |
| 551 | + mat_b.size(1), | ||
| 552 | + ")", | ||
| 553 | + " contraction axis A: ", | ||
| 554 | + a_contract_idx, | ||
| 555 | + ", contraction axis B: ", | ||
| 556 | + b_contract_idx, | ||
| 557 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 558 | + } else { | ||
| 559 | + int64_t a_col = mat_a.size(1); | ||
| 560 | + int64_t b_row = mat_b.size(0); | ||
| 561 | + TORCH_CHECK( | ||
| 562 | + a_col == b_row, | ||
| 563 | + "matrix multiplication dimension mismatch (", | ||
| 564 | + "A: ", | ||
| 565 | + mat_a.size(0), | ||
| 566 | + "x", | ||
| 567 | + mat_a.size(1), | ||
| 568 | + ", B: ", | ||
| 569 | + mat_b.size(0), | ||
| 570 | + "x", | ||
| 571 | + mat_b.size(1), | ||
| 572 | + ")", | ||
| 573 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 574 | + } | ||
| 419 | 575 | ||
| 420 | - // Check bias (reference: _scaled_mm_out_cuda) | 576 | + //////////////rowwise transfer////////////// |
| 421 | - if (bias.has_value()) { | 577 | + at::Tensor processed_scale_a = scale_a[0]; |
| 422 | - TORCH_CHECK(bias->numel() == mat_b.sizes()[1], | 578 | + at::Tensor processed_scale_b = scale_b[0]; |
| 423 | - "Bias must be size ", mat_b.sizes()[1], " but got ", bias->numel(), | 579 | + if (mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn && mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn && |
| 424 | - OPS_ERROR(ErrCode::PARAM)); | 580 | + scale_a[0].scalar_type() == c10::ScalarType::Float && scale_b[0].scalar_type() == c10::ScalarType::Float) { |
| 425 | - // Check out_dtype vs bias compatibility | 581 | + if (scale_a[0].dim() == 2 && scale_a[0].sizes()[1] == 1 && scale_b[0].dim() == 2 && scale_b[0].sizes()[0] == 1) { |
| 426 | - auto out_dtype_value = out_dtype.value_or(c10::ScalarType::BFloat16); | 582 | + TORCH_CHECK(mat_a.stride(1) == 1, "mat_a must be contiguous in last dim"); |
| 427 | - TORCH_CHECK(out_dtype_value != c10::ScalarType::Float, | 583 | + TORCH_CHECK(mat_b.stride(0) == 1, "mat_b must be contiguous in first dim"); |
| 428 | - "Bias is not supported when out_dtype is set to Float32", | 584 | + processed_scale_a = scale_a[0].squeeze(-1).contiguous(); |
| 429 | - OPS_ERROR(ErrCode::TYPE)); | 585 | + processed_scale_b = scale_b[0].squeeze(0); |
| 430 | - TORCH_CHECK(bias->scalar_type() == c10::ScalarType::BFloat16 || | ||
| 431 | - bias->scalar_type() == c10::ScalarType::Half, | ||
| 432 | - "Bias must be BFloat16 or Half, but got ", bias->scalar_type(), | ||
| 433 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 434 | - TORCH_CHECK((out_dtype_value != c10::ScalarType::Float && | ||
| 435 | - out_dtype_value != c10::ScalarType::BFloat16) || | ||
| 436 | - bias->scalar_type() == c10::ScalarType::BFloat16, | ||
| 437 | - "Bias must be BFloat16 to compute ", out_dtype_value, | ||
| 438 | - " output, but got ", bias->scalar_type(), | ||
| 439 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 440 | - TORCH_CHECK(out_dtype_value != c10::ScalarType::Half || | ||
| 441 | - bias->scalar_type() == c10::ScalarType::Half, | ||
| 442 | - "Bias must be Float16 to compute ", out_dtype_value, | ||
| 443 | - " output, but got ", bias->scalar_type(), | ||
| 444 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 445 | } | 586 | } |
| 587 | + } | ||
| 446 | 588 | ||
| 447 | - // Check out_dtype: currently only supports Float32, BFloat16, and Float16 | 589 | + //////////////parameters transfer////////////// |
| 448 | - if (out_dtype.has_value()) { | 590 | + at::Tensor x1 = mat_a; |
| 449 | - TORCH_CHECK(out_dtype.value() == c10::ScalarType::Float || | 591 | + at::Tensor x2 = mat_b; |
| 450 | - out_dtype.value() == c10::ScalarType::BFloat16 || | 592 | + c10::optional<at::Tensor> pertoken_scale = scale_a.size() > 0 ? c10::make_optional(processed_scale_a) : c10::nullopt; |
| 451 | - out_dtype.value() == c10::ScalarType::Half, | 593 | + at::Tensor scale = scale_b.size() > 0 ? processed_scale_b : at::Tensor(); |
| 452 | - "out_dtype must be Float32, BFloat16, or Float16, but got ", out_dtype.value(), | 594 | + c10::optional<int64_t> scale_dtype = c10::nullopt; // scale_b.scalar_type() |
| 453 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 454 | - } | ||
| 455 | 595 | ||
| 596 | + c10::optional<int64_t> output_dtype = ToIntType(out_dtype); | ||
| 597 | + c10::optional<at::Tensor> offset = c10::nullopt; | ||
| 598 | + c10::optional<int64_t> x1_dtype = c10::nullopt; | ||
| 599 | + c10::optional<int64_t> x2_dtype = c10::nullopt; | ||
| 600 | + c10::optional<int64_t> pertoken_scale_dtype = c10::nullopt; | ||
| 601 | + c10::OptionalIntArrayRef group_sizes = c10::nullopt; | ||
| 602 | + c10::optional<at::Tensor> y_scale = c10::nullopt; | ||
| 456 | 603 | ||
| 457 | - bool has_contraction = !contraction_dim.empty(); | 604 | + ///////////////////////////////////////////npu_quant_matmul////////////////////////////////////// |
| 458 | - if (has_contraction) { | 605 | + if (is_nz_format(x2)) { |
| 459 | - int64_t c_dim_size = static_cast<int64_t>(contraction_dim.size()); | 606 | + static const bool is_quant_matmul_weight_nz_available = check_aclnn_kernel_available("aclnnQuantMatmulWeightNz"); |
| 460 | - TORCH_CHECK(c_dim_size == 2, "contraction_dim must have exactly 2 elements", OPS_ERROR(ErrCode::PARAM)); | 607 | + TORCH_CHECK( |
| 461 | - | 608 | + is_quant_matmul_weight_nz_available, |
| 462 | - int64_t a_contract_idx = contraction_dim[0]; | 609 | + "Get aclnnQuantMatmulWeightNz or aclnnQuantMatmulWeightNzGetWorkspaceSize failed, only " |
| 463 | - int64_t b_contract_idx = contraction_dim[1]; | 610 | + "aclnnQuantMatmulWeightNz support X2's format is nz, please upgrade CANN.", |
| 464 | - int64_t a_dim_size = mat_a.size(a_contract_idx); | 611 | + OPS_ERROR(ErrCode::PARAM)); |
| 465 | - int64_t b_dim_size = mat_b.size(b_contract_idx); | 612 | + } else { |
| 466 | - | 613 | + static const bool is_quant_matmul_v5_available = check_aclnn_kernel_available("aclnnQuantMatmulV5"); |
| 467 | - TORCH_CHECK( | 614 | + TORCH_CHECK( |
| 468 | - a_dim_size == b_dim_size, | 615 | + is_quant_matmul_v5_available, |
| 469 | - "dimension mismatch for matrix multiplication (", | 616 | + "Get aclnnQuantMatmulV5 or aclnnQuantMatmulV5 failed, only " |
| 470 | - "A shape=", mat_a.size(0), "x", mat_a.size(1), | 617 | + "aclnnQuantMatmulV5 support A8W4, please upgrade CANN.", |
| 471 | - ", B shape=", mat_b.size(0), "x", mat_b.size(1), ")", | 618 | + OPS_ERROR(ErrCode::TYPE)); |
| 472 | - " contraction axis A: ", a_contract_idx, | 619 | + } |
| 473 | - ", contraction axis B: ", b_contract_idx, | 620 | + bool is_a8W4_int = x1.dtype() == at::kChar && x2.dtype() == at::kInt; |
| 474 | - OPS_ERROR(ErrCode::PARAM)); | 621 | + bool is_a8W4_float = x1.dtype() == at::kFloat8_e4m3fn && x2.dtype() == at::kFloat; |
| 475 | - } else { | 622 | + at::IntArrayRef group_size_list = group_sizes.value_or(at::IntArrayRef{}); |
| 476 | - int64_t a_col = mat_a.size(1); | 623 | + int64_t group_size = check_and_get_groups(group_size_list); |
| 477 | - int64_t b_row = mat_b.size(0); | 624 | + bool is_a4w4 = x1.dtype() == at::kInt && x2.dtype() == at::kInt; |
| 478 | - TORCH_CHECK( | 625 | + bool trans_x1 = is_transpose_last_two_dims(x1); |
| 479 | - a_col == b_row, | 626 | + bool trans_x2 = is_transpose_last_two_dims(x2); |
| 480 | - "matrix multiplication dimension mismatch (", | 627 | + auto x1_dim_num = x1.dim(); |
| 481 | - "A: ", mat_a.size(0), "x", mat_a.size(1), | 628 | + auto x2_dim_num = x2.dim(); |
| 482 | - ", B: ", mat_b.size(0), "x", mat_b.size(1), ")", | 629 | + auto x2_n_dim = (is_a4w4 && !trans_x2) ? x2.size(x2_dim_num - 1) * INT4_NUMS_IN_INT32 : x2.size(x2_dim_num - 1); |
| 483 | - OPS_ERROR(ErrCode::PARAM) | ||
| 484 | - ); | ||
| 485 | - } | ||
| 486 | - | ||
| 487 | - | ||
| 488 | - | ||
| 489 | - //////////////rowwise transfer////////////// | ||
| 490 | - at::Tensor processed_scale_a = scale_a[0]; | ||
| 491 | - at::Tensor processed_scale_b = scale_b[0]; | ||
| 492 | - if (mat_a.scalar_type() == c10::ScalarType::Float8_e4m3fn | ||
| 493 | - && mat_b.scalar_type() == c10::ScalarType::Float8_e4m3fn | ||
| 494 | - && scale_a[0].scalar_type() == c10::ScalarType::Float | ||
| 495 | - && scale_b[0].scalar_type() == c10::ScalarType::Float) { | ||
| 496 | - if (scale_a[0].dim() == 2 && scale_a[0].sizes()[1] == 1 && scale_b[0].dim() == 2 && scale_b[0].sizes()[0] == 1) { | ||
| 497 | - TORCH_CHECK(mat_a.stride(1) == 1, "mat_a must be contiguous in last dim"); | ||
| 498 | - TORCH_CHECK(mat_b.stride(0) == 1, "mat_b must be contiguous in first dim"); | ||
| 499 | - processed_scale_a = scale_a[0].squeeze(-1).contiguous(); | ||
| 500 | - processed_scale_b = scale_b[0].squeeze(0); | ||
| 501 | - } | ||
| 502 | - } | ||
| 503 | - | ||
| 504 | - //////////////parameters transfer////////////// | ||
| 505 | - at::Tensor x1 = mat_a; | ||
| 506 | - at::Tensor x2 = mat_b; | ||
| 507 | - c10::optional<at::Tensor> pertoken_scale = scale_a.size() > 0 ? c10::make_optional(processed_scale_a) : c10::nullopt; | ||
| 508 | - at::Tensor scale = scale_b.size() > 0 ? processed_scale_b : at::Tensor(); | ||
| 509 | - c10::optional<int64_t> scale_dtype = c10::nullopt; // scale_b.scalar_type() | ||
| 510 | - | ||
| 511 | - c10::optional<int64_t> output_dtype = ToIntType(out_dtype); | ||
| 512 | - c10::optional<at::Tensor> offset = c10::nullopt; | ||
| 513 | - c10::optional<int64_t> x1_dtype = c10::nullopt; | ||
| 514 | - c10::optional<int64_t> x2_dtype = c10::nullopt; | ||
| 515 | - c10::optional<int64_t> pertoken_scale_dtype = c10::nullopt; | ||
| 516 | - c10::OptionalIntArrayRef group_sizes = c10::nullopt; | ||
| 517 | - c10::optional<at::Tensor> y_scale = c10::nullopt; | ||
| 518 | - | ||
| 519 | - | ||
| 520 | - ///////////////////////////////////////////npu_quant_matmul////////////////////////////////////// | ||
| 521 | - if (is_nz_format(x2)) { | ||
| 522 | - static const bool is_quant_matmul_weight_nz_available = check_aclnn_kernel_available("aclnnQuantMatmulWeightNz"); | ||
| 523 | - TORCH_CHECK(is_quant_matmul_weight_nz_available, | ||
| 524 | - "Get aclnnQuantMatmulWeightNz or aclnnQuantMatmulWeightNzGetWorkspaceSize failed, only " | ||
| 525 | - "aclnnQuantMatmulWeightNz support X2's format is nz, please upgrade CANN.", | ||
| 526 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 527 | - } else { | ||
| 528 | - static const bool is_quant_matmul_v5_available = check_aclnn_kernel_available("aclnnQuantMatmulV5"); | ||
| 529 | - TORCH_CHECK(is_quant_matmul_v5_available, | ||
| 530 | - "Get aclnnQuantMatmulV5 or aclnnQuantMatmulV5 failed, only " | ||
| 531 | - "aclnnQuantMatmulV5 support A8W4, please upgrade CANN.", | ||
| 532 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 533 | - } | ||
| 534 | - bool is_a8W4_int = x1.dtype() == at::kChar && x2.dtype() == at::kInt; | ||
| 535 | - bool is_a8W4_float = x1.dtype() == at::kFloat8_e4m3fn && x2.dtype() == at::kFloat; | ||
| 536 | - at::IntArrayRef group_size_list = group_sizes.value_or(at::IntArrayRef{}); | ||
| 537 | - int64_t group_size = check_and_get_groups(group_size_list); | ||
| 538 | - bool is_a4w4 = x1.dtype() == at::kInt && x2.dtype() == at::kInt; | ||
| 539 | - bool trans_x1 = is_transpose_last_two_dims(x1); | ||
| 540 | - bool trans_x2 = is_transpose_last_two_dims(x2); | ||
| 541 | - auto x1_dim_num = x1.dim(); | ||
| 542 | - auto x2_dim_num = x2.dim(); | ||
| 543 | - auto x2_n_dim = (is_a4w4 && !trans_x2) ? x2.size(x2_dim_num - 1) * INT4_NUMS_IN_INT32 : x2.size(x2_dim_num - 1); | ||
| 544 | 630 | ||
| 545 | 631 | ||
| 546 | - bool mxfp4_valid = x1_dtype.has_value() && x2_dtype.has_value() && | 632 | + bool mxfp4_valid = x1_dtype.has_value() && x2_dtype.has_value() && |
| 547 | - x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) && | 633 | + x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) && |
| 548 | - x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); | 634 | + x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); |
| 549 | 635 | ||
| 550 | 636 | ||
| 551 | - bool mxfp4_valid = false; | 637 | + bool mxfp4_valid = false; |
| 552 | - if (x1_dtype.has_value()) { | 638 | + if (x1_dtype.has_value()) { |
| 553 | - mxfp4_valid = x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); | 639 | + mxfp4_valid = x1_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); |
| 554 | - } else { | 640 | + } else { |
| 555 | - mxfp4_valid = x1.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; | 641 | + mxfp4_valid = x1.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; |
| 556 | - } | 642 | + } |
| 557 | - if (x2_dtype.has_value()) { | 643 | + if (x2_dtype.has_value()) { |
| 558 | - mxfp4_valid = mxfp4_valid && x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); | 644 | + mxfp4_valid = mxfp4_valid && x2_dtype.value() == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1); |
| 559 | - } else { | 645 | + } else { |
| 560 | - mxfp4_valid = mxfp4_valid && x2.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; | 646 | + mxfp4_valid = mxfp4_valid && x2.scalar_type() == at::ScalarType::Float4_e2m1fn_x2; |
| 561 | - } | 647 | + } |
| 562 | 648 | ||
| 563 | 649 | ||
| 564 | - c10::SmallVector<int64_t, SIZE> output_size; | 650 | + c10::SmallVector<int64_t, SIZE> output_size; |
| 565 | - if (is_a8W4_int) { | 651 | + if (is_a8W4_int) { |
| 566 | - output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; | 652 | + output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; |
| 567 | - } else if (is_a8W4_float) { | 653 | + } else if (is_a8W4_float) { |
| 568 | - if (trans_x2) { | 654 | + if (trans_x2) { |
| 569 | - output_size = {x1.sizes()[0], x2.sizes()[1]}; | 655 | + output_size = {x1.sizes()[0], x2.sizes()[1]}; |
| 570 | - } else { | ||
| 571 | - output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; | ||
| 572 | - } | ||
| 573 | } else { | 656 | } else { |
| 574 | - std::vector<uint64_t> batch_record; | 657 | + output_size = {x1.sizes()[0], x2.sizes()[1] * INT4_NUMS_IN_INT32}; |
| 575 | - uint64_t batch_val = infer_out_batch_shape(x1, x2, batch_record); | ||
| 576 | - const at::Tensor long_tensor = x1_dim_num > x2_dim_num ? x1 : x2; | ||
| 577 | - output_size = op_infer::array_to_small_vector(long_tensor.sizes()); | ||
| 578 | - if (mxfp4_valid) { | ||
| 579 | - TORCH_CHECK(x1.dim() >= 2 && x1.dim() <= 6, | ||
| 580 | - "x1 dim num should be 2 ~ 6, please check x1 dim num. Actual x1 dim = ", x1.dim(), | ||
| 581 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 582 | - TORCH_CHECK(x2.dim() >= 2 && x2.dim() <= 6, | ||
| 583 | - "x2 dim num should be 2 ~ 6, please check x2 dim num. Actual x2 dim = ", x2.dim(), | ||
| 584 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 585 | - int64_t x1_size_last_second = x1.sizes()[x1_dim_num - LAST_SECOND_DIM_INDEX]; | ||
| 586 | - int64_t x2_size_last = x2.sizes()[x2_dim_num - 1]; | ||
| 587 | - int64_t real_m = !trans_x1 ? x1_size_last_second : x1_size_last_second * FP4_IN_INT8; | ||
| 588 | - int64_t real_n = trans_x2 ? x2_size_last : x2_size_last * FP4_IN_INT8; | ||
| 589 | - output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = real_m; | ||
| 590 | - output_size[long_tensor.dim() - 1] = real_n; | ||
| 591 | - } else { | ||
| 592 | - output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = x1.size(x1_dim_num - LAST_SECOND_DIM_INDEX); | ||
| 593 | - output_size[long_tensor.dim() - 1] = x2_n_dim; | ||
| 594 | - } | ||
| 595 | - for (int64_t i = 0; i < long_tensor.dim() - LAST_SECOND_DIM_INDEX; i++) { | ||
| 596 | - output_size[i] = static_cast<int64_t>(batch_record[i]); | ||
| 597 | - } | ||
| 598 | } | 658 | } |
| 599 | - c10::TensorOptions options; | 659 | + } else { |
| 600 | - aclDataType output_acltype = ACL_INT8; | 660 | + std::vector<uint64_t> batch_record; |
| 601 | - if (!output_dtype.has_value()) { | 661 | + uint64_t batch_val = infer_out_batch_shape(x1, x2, batch_record); |
| 602 | - options = x1.options().dtype(at::kChar); | 662 | + const at::Tensor long_tensor = x1_dim_num > x2_dim_num ? x1 : x2; |
| 663 | + output_size = op_infer::array_to_small_vector(long_tensor.sizes()); | ||
| 664 | + if (mxfp4_valid) { | ||
| 665 | + TORCH_CHECK( | ||
| 666 | + x1.dim() >= 2 && x1.dim() <= 6, | ||
| 667 | + "x1 dim num should be 2 ~ 6, please check x1 dim num. Actual x1 dim = ", | ||
| 668 | + x1.dim(), | ||
| 669 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 670 | + TORCH_CHECK( | ||
| 671 | + x2.dim() >= 2 && x2.dim() <= 6, | ||
| 672 | + "x2 dim num should be 2 ~ 6, please check x2 dim num. Actual x2 dim = ", | ||
| 673 | + x2.dim(), | ||
| 674 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 675 | + int64_t x1_size_last_second = x1.sizes()[x1_dim_num - LAST_SECOND_DIM_INDEX]; | ||
| 676 | + int64_t x2_size_last = x2.sizes()[x2_dim_num - 1]; | ||
| 677 | + int64_t real_m = !trans_x1 ? x1_size_last_second : x1_size_last_second * FP4_IN_INT8; | ||
| 678 | + int64_t real_n = trans_x2 ? x2_size_last : x2_size_last * FP4_IN_INT8; | ||
| 679 | + output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = real_m; | ||
| 680 | + output_size[long_tensor.dim() - 1] = real_n; | ||
| 603 | } else { | 681 | } else { |
| 604 | - output_acltype = c10_npu::GetAclDataType(output_dtype.value()); | 682 | + output_size[long_tensor.dim() - LAST_SECOND_DIM_INDEX] = x1.size(x1_dim_num - LAST_SECOND_DIM_INDEX); |
| 605 | - options = x1.options().dtype(npu_preparation::convert_to_scalar_type(output_acltype)); | 683 | + output_size[long_tensor.dim() - 1] = x2_n_dim; |
| 606 | } | 684 | } |
| 607 | - at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, options); | 685 | + for (int64_t i = 0; i < long_tensor.dim() - LAST_SECOND_DIM_INDEX; i++) { |
| 686 | + output_size[i] = static_cast<int64_t>(batch_record[i]); | ||
| 687 | + } | ||
| 688 | + } | ||
| 689 | + c10::TensorOptions options; | ||
| 690 | + aclDataType output_acltype = ACL_INT8; | ||
| 691 | + if (!output_dtype.has_value()) { | ||
| 692 | + options = x1.options().dtype(at::kChar); | ||
| 693 | + } else { | ||
| 694 | + output_acltype = c10_npu::GetAclDataType(output_dtype.value()); | ||
| 695 | + options = x1.options().dtype(npu_preparation::convert_to_scalar_type(output_acltype)); | ||
| 696 | + } | ||
| 697 | + at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, options); | ||
| 608 | 698 | ||
| 609 | - const at::Tensor &offset_real = offset.value_or(at::Tensor()); | 699 | + const at::Tensor& offset_real = offset.value_or(at::Tensor()); |
| 610 | - const at::Tensor &pertoken_scale_real = pertoken_scale.value_or(at::Tensor()); | 700 | + const at::Tensor& pertoken_scale_real = pertoken_scale.value_or(at::Tensor()); |
| 611 | - const at::Tensor &bias_real = bias.value_or(at::Tensor()); | 701 | + const at::Tensor& bias_real = bias.value_or(at::Tensor()); |
| 612 | - bool transpose1 = false; | 702 | + bool transpose1 = false; |
| 613 | - bool transpose2 = false; | 703 | + bool transpose2 = false; |
| 614 | 704 | ||
| 615 | - TensorWrapper x1_wrapper = make_wrapper(x1, x1_dtype); | 705 | + TensorWrapper x1_wrapper = make_wrapper(x1, x1_dtype); |
| 616 | - TensorWrapper x2_wrapper = make_wrapper(x2, x2_dtype); | 706 | + TensorWrapper x2_wrapper = make_wrapper(x2, x2_dtype); |
| 617 | - TensorWrapper x1_scale_wrapper = make_wrapper(pertoken_scale_real, pertoken_scale_dtype); | 707 | + TensorWrapper x1_scale_wrapper = make_wrapper(pertoken_scale_real, pertoken_scale_dtype); |
| 618 | - TensorWrapper x2_scale_wrapper = make_wrapper(scale, scale_dtype); | 708 | + TensorWrapper x2_scale_wrapper = make_wrapper(scale, scale_dtype); |
| 619 | - TensorWrapper result_wrapper = make_wrapper(result, output_dtype); | 709 | + TensorWrapper result_wrapper = make_wrapper(result, output_dtype); |
| 620 | - at::Tensor x1_offset = at::empty({0}, options); | 710 | + at::Tensor x1_offset = at::empty({0}, options); |
| 621 | - at::Tensor x2_offset = at::Tensor(); | 711 | + at::Tensor x2_offset = at::Tensor(); |
| 622 | - at::Tensor y_offset = at::empty({0}, options); | 712 | + at::Tensor y_offset = at::empty({0}, options); |
| 623 | - if (is_a8W4_int) { // Only A8W4 int needs y_offset | 713 | + if (is_a8W4_int) { // Only A8W4 int needs y_offset |
| 624 | - y_offset = offset_real; | 714 | + y_offset = offset_real; |
| 715 | + } else { | ||
| 716 | + x2_offset = offset_real; | ||
| 717 | + } | ||
| 718 | + | ||
| 719 | + bool use_aclnn_v5 = | ||
| 720 | + x1_dtype.has_value() || (x1.dtype() != at::kInt && x1.dtype() != at::kChar) || is_a8W4_float || is_a8W4_int; | ||
| 721 | + | ||
| 722 | + aclDataType pertoken_scale_dtype_real = pertoken_scale_dtype.has_value() | ||
| 723 | + ? c10_npu::GetAclDataType(pertoken_scale_dtype.value()) | ||
| 724 | + : (pertoken_scale.has_value() ? c10_npu::GetAclDataType(static_cast<int64_t>(pertoken_scale_real.scalar_type())) | ||
| 725 | + : aclDataType::ACL_INT8); | ||
| 726 | + bool need_check_trans = pertoken_scale.has_value() && | ||
| 727 | + (((pertoken_scale_real.dim() == x1.dim() && scale.dim() == x2.dim()) || | ||
| 728 | + pertoken_scale_dtype_real == aclDataType::ACL_FLOAT8_E8M0) && | ||
| 729 | + (pertoken_scale_real.dim() >= 2 && scale.dim() >= 2)) && | ||
| 730 | + !(is_a8W4_float || is_a8W4_int); | ||
| 731 | + if (need_check_trans) { | ||
| 732 | + int64_t dim_x1 = x1.dim() - 2; // check the last 2 dim | ||
| 733 | + int64_t dim_x2 = x2.dim() - 2; // check the last 2 dim | ||
| 734 | + int64_t dim_x1_scale = 0; | ||
| 735 | + int64_t dim_x2_scale = 0; | ||
| 736 | + if (pertoken_scale_dtype_real != aclDataType::ACL_FLOAT8_E8M0) { | ||
| 737 | + dim_x1_scale = pertoken_scale_real.dim() - 2; // check the last 2 dim in GB/BB | ||
| 738 | + dim_x2_scale = scale.dim() - 2; // check the last 2 dim in GB/BB | ||
| 739 | + } | ||
| 740 | + TORCH_CHECK( | ||
| 741 | + is_x_scale_same_transpose(x1, pertoken_scale_real, dim_x1, dim_x1_scale), | ||
| 742 | + "Input x1 tensor and pertoken_scale tensor's transpose are not same, please check input.", | ||
| 743 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 744 | + TORCH_CHECK( | ||
| 745 | + is_x_scale_same_transpose(x2, scale, dim_x2, dim_x2_scale), | ||
| 746 | + "Input x2 tensor and scale tensor's transpose are not same, please check input.", | ||
| 747 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 748 | + } | ||
| 749 | + | ||
| 750 | + bool use_trans_quant_param = scale.dtype() == at::kFloat && !pertoken_scale.has_value() && | ||
| 751 | + (output_acltype != ACL_BF16 || use_aclnn_v5) && output_acltype != ACL_INT32; | ||
| 752 | + if (use_trans_quant_param) { | ||
| 753 | + const at::Tensor quant_param = op_api::npu_trans_quant_param(scale, offset); | ||
| 754 | + if (is_nz_format(x2)) { | ||
| 755 | + EXEC_NPU_CMD( | ||
| 756 | + aclnnQuantMatmulWeightNz, | ||
| 757 | + x1_wrapper, | ||
| 758 | + x2_wrapper, | ||
| 759 | + pertoken_scale_real, | ||
| 760 | + quant_param, | ||
| 761 | + y_scale, | ||
| 762 | + x1_offset, | ||
| 763 | + x2_offset, | ||
| 764 | + y_offset, | ||
| 765 | + bias_real, | ||
| 766 | + transpose1, | ||
| 767 | + transpose2, | ||
| 768 | + group_size, | ||
| 769 | + result_wrapper); | ||
| 625 | } else { | 770 | } else { |
| 626 | - x2_offset = offset_real; | 771 | + EXEC_NPU_CMD( |
| 772 | + aclnnQuantMatmulV5, | ||
| 773 | + x1_wrapper, | ||
| 774 | + x2_wrapper, | ||
| 775 | + pertoken_scale_real, | ||
| 776 | + quant_param, | ||
| 777 | + y_scale, | ||
| 778 | + x1_offset, | ||
| 779 | + x2_offset, | ||
| 780 | + y_offset, | ||
| 781 | + bias_real, | ||
| 782 | + transpose1, | ||
| 783 | + transpose2, | ||
| 784 | + group_size, | ||
| 785 | + result_wrapper); | ||
| 627 | } | 786 | } |
| 628 | - | 787 | + } else { |
| 629 | - bool use_aclnn_v5 = x1_dtype.has_value() || (x1.dtype() != at::kInt && x1.dtype() != at::kChar) || | 788 | + if (!is_a4w4 && is_nz_format(x2)) { |
| 630 | - is_a8W4_float || is_a8W4_int; | 789 | + EXEC_NPU_CMD( |
| 631 | - | 790 | + aclnnQuantMatmulWeightNz, |
| 632 | - aclDataType pertoken_scale_dtype_real = pertoken_scale_dtype.has_value() | 791 | + x1_wrapper, |
| 633 | - ? c10_npu::GetAclDataType(pertoken_scale_dtype.value()) | 792 | + x2_wrapper, |
| 634 | - : (pertoken_scale.has_value() | 793 | + x1_scale_wrapper, |
| 635 | - ? c10_npu::GetAclDataType(static_cast<int64_t>(pertoken_scale_real.scalar_type())) | 794 | + x2_scale_wrapper, |
| 636 | - : aclDataType::ACL_INT8); | 795 | + y_scale, |
| 637 | - bool need_check_trans = pertoken_scale.has_value() | 796 | + x1_offset, |
| 638 | - && (((pertoken_scale_real.dim() == x1.dim() && scale.dim() == x2.dim()) | 797 | + x2_offset, |
| 639 | - || pertoken_scale_dtype_real == aclDataType::ACL_FLOAT8_E8M0) | 798 | + y_offset, |
| 640 | - && (pertoken_scale_real.dim() >= 2 && scale.dim() >= 2)) | 799 | + bias_real, |
| 641 | - && !(is_a8W4_float || is_a8W4_int); | 800 | + transpose1, |
| 642 | - if (need_check_trans) { | 801 | + transpose2, |
| 643 | - int64_t dim_x1 = x1.dim() - 2; // check the last 2 dim | 802 | + group_size, |
| 644 | - int64_t dim_x2 = x2.dim() - 2; // check the last 2 dim | 803 | + result_wrapper); |
| 645 | - int64_t dim_x1_scale = 0; | ||
| 646 | - int64_t dim_x2_scale = 0; | ||
| 647 | - if (pertoken_scale_dtype_real != aclDataType::ACL_FLOAT8_E8M0) { | ||
| 648 | - dim_x1_scale = pertoken_scale_real.dim() - 2; // check the last 2 dim in GB/BB | ||
| 649 | - dim_x2_scale = scale.dim() - 2; // check the last 2 dim in GB/BB | ||
| 650 | - } | ||
| 651 | - TORCH_CHECK(is_x_scale_same_transpose(x1, pertoken_scale_real, dim_x1, dim_x1_scale), | ||
| 652 | - "Input x1 tensor and pertoken_scale tensor's transpose are not same, please check input.", | ||
| 653 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 654 | - TORCH_CHECK(is_x_scale_same_transpose(x2, scale, dim_x2, dim_x2_scale), | ||
| 655 | - "Input x2 tensor and scale tensor's transpose are not same, please check input.", | ||
| 656 | - OPS_ERROR(ErrCode::PARAM)); | ||
| 657 | - } | ||
| 658 | - | ||
| 659 | - bool use_trans_quant_param = scale.dtype() == at::kFloat && !pertoken_scale.has_value() && | ||
| 660 | - (output_acltype != ACL_BF16 || use_aclnn_v5) && output_acltype != ACL_INT32; | ||
| 661 | - if (use_trans_quant_param) { | ||
| 662 | - const at::Tensor quant_param = op_api::npu_trans_quant_param(scale, offset); | ||
| 663 | - if (is_nz_format(x2)) { | ||
| 664 | - EXEC_NPU_CMD(aclnnQuantMatmulWeightNz, x1_wrapper, x2_wrapper, pertoken_scale_real, quant_param, y_scale, | ||
| 665 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | ||
| 666 | - } else { | ||
| 667 | - EXEC_NPU_CMD(aclnnQuantMatmulV5, x1_wrapper, x2_wrapper, pertoken_scale_real, quant_param, y_scale, | ||
| 668 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | ||
| 669 | - } | ||
| 670 | } else { | 804 | } else { |
| 671 | - if (!is_a4w4 && is_nz_format(x2)) { | 805 | + EXEC_NPU_CMD( |
| 672 | - EXEC_NPU_CMD(aclnnQuantMatmulWeightNz, x1_wrapper, x2_wrapper, x1_scale_wrapper, x2_scale_wrapper, y_scale, | 806 | + aclnnQuantMatmulV5, |
| 673 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | 807 | + x1_wrapper, |
| 674 | - } else { | 808 | + x2_wrapper, |
| 675 | - EXEC_NPU_CMD(aclnnQuantMatmulV5, x1_wrapper, x2_wrapper, x1_scale_wrapper, x2_scale_wrapper, y_scale, | 809 | + x1_scale_wrapper, |
| 676 | - x1_offset, x2_offset, y_offset, bias_real, transpose1, transpose2, group_size, result_wrapper); | 810 | + x2_scale_wrapper, |
| 677 | - } | 811 | + y_scale, |
| 812 | + x1_offset, | ||
| 813 | + x2_offset, | ||
| 814 | + y_offset, | ||
| 815 | + bias_real, | ||
| 816 | + transpose1, | ||
| 817 | + transpose2, | ||
| 818 | + group_size, | ||
| 819 | + result_wrapper); | ||
| 678 | } | 820 | } |
| 821 | + } | ||
| 679 | 822 | ||
| 680 | - return result; | 823 | + return result; |
| 681 | } | 824 | } |
| 682 | 825 | ||
| 683 | -} | 826 | +} // namespace op_api |
| @@ -17,45 +17,29 @@ | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | - | ||
| 21 | namespace op_api { | 20 | namespace op_api { |
| 22 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 23 | 22 | ||
| 24 | -at::Tensor scatter_add( | 23 | +at::Tensor scatter_add(const at::Tensor& self, int64_t dim, const at::Tensor& index, const at::Tensor& src) { |
| 25 | - const at::Tensor& self, | 24 | + DO_COMPATIBILITY(aclnnScatterAdd, acl_op::scatter_add(self, dim, index, src)); |
| 26 | - int64_t dim, | 25 | + auto selfClone = self.clone(at::MemoryFormat::Contiguous); |
| 27 | - const at::Tensor& index, | 26 | + npu_preparation::CheckMemory({selfClone, index, src}, {selfClone}); |
| 28 | - const at::Tensor& src) | 27 | + EXEC_NPU_CMD(aclnnScatterAdd, selfClone, dim, index, src, selfClone); |
| 29 | -{ | 28 | + return selfClone; |
| 30 | - DO_COMPATIBILITY(aclnnScatterAdd, acl_op::scatter_add(self, dim, index, src)); | ||
| 31 | - auto selfClone = self.clone(at::MemoryFormat::Contiguous); | ||
| 32 | - npu_preparation::CheckMemory({selfClone, index, src}, {selfClone}); | ||
| 33 | - EXEC_NPU_CMD(aclnnScatterAdd, selfClone, dim, index, src, selfClone); | ||
| 34 | - return selfClone; | ||
| 35 | } | 29 | } |
| 36 | 30 | ||
| 37 | -at::Tensor& scatter_add_( | 31 | +at::Tensor& scatter_add_(at::Tensor& self, int64_t dim, const at::Tensor& index, const at::Tensor& src) { |
| 38 | - at::Tensor& self, | 32 | + DO_COMPATIBILITY(aclnnScatterAdd, acl_op::scatter_add_(self, dim, index, src)); |
| 39 | - int64_t dim, | 33 | + npu_preparation::CheckMemory({self, index, src}, {self}); |
| 40 | - const at::Tensor& index, | 34 | + EXEC_NPU_CMD(aclnnScatterAdd, self, dim, index, src, self); |
| 41 | - const at::Tensor& src) | 35 | + return self; |
| 42 | -{ | ||
| 43 | - DO_COMPATIBILITY(aclnnScatterAdd, acl_op::scatter_add_(self, dim, index, src)); | ||
| 44 | - npu_preparation::CheckMemory({self, index, src}, {self}); | ||
| 45 | - EXEC_NPU_CMD(aclnnScatterAdd, self, dim, index, src, self); | ||
| 46 | - return self; | ||
| 47 | } | 36 | } |
| 48 | 37 | ||
| 49 | 38 | ||
| 50 | -at::Tensor scatter_add( | 39 | +at::Tensor scatter_add(const at::Tensor& self, at::Dimname dim, const at::Tensor& index, const at::Tensor& src) { |
| 51 | - const at::Tensor& self, | 40 | + DO_COMPATIBILITY(aclnnScatterAdd, acl_op::scatter_add(self, dim, index, src)); |
| 52 | - at::Dimname dim, | 41 | + return op_api::scatter_add(self, dimname_to_position(self, dim), index, src); |
| 53 | - const at::Tensor& index, | ||
| 54 | - const at::Tensor& src) | ||
| 55 | -{ | ||
| 56 | - DO_COMPATIBILITY(aclnnScatterAdd, acl_op::scatter_add(self, dim, index, src)); | ||
| 57 | - return op_api::scatter_add(self, dimname_to_position(self, dim), index, src); | ||
| 58 | } | 42 | } |
| 59 | 43 | ||
| 60 | 44 | ||
| 61 | -} | 45 | +} // namespace op_api |
| @@ -21,76 +21,86 @@ namespace op_api { | |||
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | // reduce value must be "add" or "multiply" | 23 | // reduce value must be "add" or "multiply" |
| 24 | -static inline bool reduce_valid(c10::string_view reduce) | 24 | +static inline bool reduce_valid(c10::string_view reduce) { |
| 25 | -{ | 25 | + return (reduce == "add" || reduce == "multiply"); |
| 26 | - return (reduce == "add" || reduce == "multiply"); | ||
| 27 | } | 26 | } |
| 28 | 27 | ||
| 29 | -static int64_t get_reduce(c10::string_view reduce) | 28 | +static int64_t get_reduce(c10::string_view reduce) { |
| 30 | -{ | 29 | + if (reduce == "add") { |
| 31 | - if (reduce == "add") { | 30 | + return 1; |
| 32 | - return 1; | 31 | + } else if (reduce == "multiply") { |
| 33 | - } else if (reduce == "multiply") { | 32 | + return 2; |
| 34 | - return 2; | 33 | + } |
| 35 | - } | 34 | + return 0; |
| 36 | - return 0; | ||
| 37 | } | 35 | } |
| 38 | 36 | ||
| 39 | -at::Tensor& scatter_out(const at::Tensor& self, int64_t dim, const at::Tensor& index, | 37 | +at::Tensor& scatter_out( |
| 40 | - const at::Tensor& src, at::Tensor& out) | 38 | + const at::Tensor& self, |
| 41 | -{ | 39 | + int64_t dim, |
| 42 | - DO_COMPATIBILITY(aclnnScatter, acl_op::scatter_out(self, dim, index, src, out)); | 40 | + const at::Tensor& index, |
| 43 | - npu_preparation::check_tensor({self, src, index}, out, self); | 41 | + const at::Tensor& src, |
| 44 | - int64_t reduction = 0; | 42 | + at::Tensor& out) { |
| 45 | - EXEC_NPU_CMD(aclnnScatter, self, dim, index, src, reduction, out); | 43 | + DO_COMPATIBILITY(aclnnScatter, acl_op::scatter_out(self, dim, index, src, out)); |
| 46 | - return out; | 44 | + npu_preparation::check_tensor({self, src, index}, out, self); |
| 45 | + int64_t reduction = 0; | ||
| 46 | + EXEC_NPU_CMD(aclnnScatter, self, dim, index, src, reduction, out); | ||
| 47 | + return out; | ||
| 47 | } | 48 | } |
| 48 | 49 | ||
| 49 | -at::Tensor& scatter_out(const at::Tensor& self, int64_t dim, const at::Tensor& index, | 50 | +at::Tensor& scatter_out( |
| 50 | - const at::Tensor& src, c10::string_view reduce, at::Tensor& out) | 51 | + const at::Tensor& self, |
| 51 | -{ | 52 | + int64_t dim, |
| 52 | - npu_preparation::check_tensor({self, src, index}, out, self); | 53 | + const at::Tensor& index, |
| 53 | - TORCH_CHECK(reduce_valid(reduce), "Reduce should be either add or multiply", OPS_ERROR(ErrCode::PARAM)); | 54 | + const at::Tensor& src, |
| 54 | - int64_t reduction = get_reduce(reduce); | 55 | + c10::string_view reduce, |
| 55 | - EXEC_NPU_CMD(aclnnScatter, self, dim, index, src, reduction, out); | 56 | + at::Tensor& out) { |
| 56 | - return out; | 57 | + npu_preparation::check_tensor({self, src, index}, out, self); |
| 58 | + TORCH_CHECK(reduce_valid(reduce), "Reduce should be either add or multiply", OPS_ERROR(ErrCode::PARAM)); | ||
| 59 | + int64_t reduction = get_reduce(reduce); | ||
| 60 | + EXEC_NPU_CMD(aclnnScatter, self, dim, index, src, reduction, out); | ||
| 61 | + return out; | ||
| 57 | } | 62 | } |
| 58 | 63 | ||
| 59 | -at::Tensor& scatter_out(const at::Tensor& self, int64_t dim, const at::Tensor& index, | 64 | +at::Tensor& scatter_out( |
| 60 | - const at::Scalar& value, at::Tensor& out) | 65 | + const at::Tensor& self, |
| 61 | -{ | 66 | + int64_t dim, |
| 62 | - DO_COMPATIBILITY(aclnnScatterValue, acl_op::scatter_out(self, dim, index, value, out)); | 67 | + const at::Tensor& index, |
| 63 | - npu_preparation::check_tensor({self, index}, out, self); | 68 | + const at::Scalar& value, |
| 64 | - int64_t reduction = 0; | 69 | + at::Tensor& out) { |
| 65 | - EXEC_NPU_CMD(aclnnScatterValue, self, dim, index, value, reduction, out); | 70 | + DO_COMPATIBILITY(aclnnScatterValue, acl_op::scatter_out(self, dim, index, value, out)); |
| 66 | - return out; | 71 | + npu_preparation::check_tensor({self, index}, out, self); |
| 72 | + int64_t reduction = 0; | ||
| 73 | + EXEC_NPU_CMD(aclnnScatterValue, self, dim, index, value, reduction, out); | ||
| 74 | + return out; | ||
| 67 | } | 75 | } |
| 68 | 76 | ||
| 69 | -at::Tensor& scatter_out(const at::Tensor& self, int64_t dim, const at::Tensor& index, | 77 | +at::Tensor& scatter_out( |
| 70 | - const at::Scalar& value, c10::string_view reduce, at::Tensor& out) | 78 | + const at::Tensor& self, |
| 71 | -{ | 79 | + int64_t dim, |
| 72 | - npu_preparation::check_tensor({self, index}, out, self); | 80 | + const at::Tensor& index, |
| 73 | - TORCH_CHECK(reduce_valid(reduce), "Reduce should be either add or multiply", OPS_ERROR(ErrCode::PARAM)); | 81 | + const at::Scalar& value, |
| 74 | - int64_t reduction = get_reduce(reduce); | 82 | + c10::string_view reduce, |
| 75 | - EXEC_NPU_CMD(aclnnScatterValue, self, dim, index, value, reduction, out); | 83 | + at::Tensor& out) { |
| 76 | - return out; | 84 | + npu_preparation::check_tensor({self, index}, out, self); |
| 85 | + TORCH_CHECK(reduce_valid(reduce), "Reduce should be either add or multiply", OPS_ERROR(ErrCode::PARAM)); | ||
| 86 | + int64_t reduction = get_reduce(reduce); | ||
| 87 | + EXEC_NPU_CMD(aclnnScatterValue, self, dim, index, value, reduction, out); | ||
| 88 | + return out; | ||
| 77 | } | 89 | } |
| 78 | 90 | ||
| 79 | -at::Tensor &scatter_(at::Tensor &self, int64_t dim, const at::Tensor &index, const at::Tensor &src) | 91 | +at::Tensor& scatter_(at::Tensor& self, int64_t dim, const at::Tensor& index, const at::Tensor& src) { |
| 80 | -{ | 92 | + DO_COMPATIBILITY(aclnnInplaceScatter, acl_op::scatter_(self, dim, index, src)); |
| 81 | - DO_COMPATIBILITY(aclnnInplaceScatter, acl_op::scatter_(self, dim, index, src)); | 93 | + npu_preparation::check_tensor({self, src, index}, self, self); |
| 82 | - npu_preparation::check_tensor({self, src, index}, self, self); | 94 | + int64_t reduction = 0; |
| 83 | - int64_t reduction = 0; | 95 | + EXEC_NPU_CMD(aclnnInplaceScatter, self, dim, index, src, reduction); |
| 84 | - EXEC_NPU_CMD(aclnnInplaceScatter, self, dim, index, src, reduction); | 96 | + return self; |
| 85 | - return self; | ||
| 86 | } | 97 | } |
| 87 | 98 | ||
| 88 | -at::Tensor &scatter_(at::Tensor &self, int64_t dim, const at::Tensor &index, const at::Scalar& value) | 99 | +at::Tensor& scatter_(at::Tensor& self, int64_t dim, const at::Tensor& index, const at::Scalar& value) { |
| 89 | -{ | 100 | + DO_COMPATIBILITY(aclnnInplaceScatterValue, acl_op::scatter_(self, dim, index, value)); |
| 90 | - DO_COMPATIBILITY(aclnnInplaceScatterValue, acl_op::scatter_(self, dim, index, value)); | 101 | + npu_preparation::check_tensor({self, index}, self, self); |
| 91 | - npu_preparation::check_tensor({self, index}, self, self); | 102 | + int64_t reduction = 0; |
| 92 | - int64_t reduction = 0; | 103 | + EXEC_NPU_CMD(aclnnInplaceScatterValue, self, dim, index, value, reduction); |
| 93 | - EXEC_NPU_CMD(aclnnInplaceScatterValue, self, dim, index, value, reduction); | 104 | + return self; |
| 94 | - return self; | ||
| 95 | -} | ||
| 96 | } | 105 | } |
| 106 | +} // namespace op_api | ||
| @@ -18,42 +18,40 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | - using npu_preparation = at_npu::native::OpPreparation; | 21 | +using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | - std::vector<at::Tensor> npu_scatter_list( | 23 | +std::vector<at::Tensor> npu_scatter_list( |
| 24 | - at::TensorList self, | 24 | + at::TensorList self, |
| 25 | - const at::Tensor &indice, | 25 | + const at::Tensor& indice, |
| 26 | - const at::Tensor &updates, | 26 | + const at::Tensor& updates, |
| 27 | - const c10::optional<at::Tensor> &mask, | 27 | + const c10::optional<at::Tensor>& mask, |
| 28 | - c10::string_view reduce, | 28 | + c10::string_view reduce, |
| 29 | - int64_t axis) | 29 | + int64_t axis) { |
| 30 | - { | 30 | + std::string reduce_str = std::string(reduce); |
| 31 | - std::string reduce_str = std::string(reduce); | 31 | + char* reduce_ptr = const_cast<char*>(reduce_str.c_str()); |
| 32 | - char *reduce_ptr = const_cast<char *>(reduce_str.c_str()); | 32 | + // The attribute 'reduce' of ScatterList only supports setting it to 'update'. |
| 33 | - // The attribute 'reduce' of ScatterList only supports setting it to 'update'. | 33 | + std::vector<at::Tensor> result; |
| 34 | - std::vector<at::Tensor> result; | 34 | + for (const at::Tensor& tensor : self) { |
| 35 | - for (const at::Tensor &tensor : self) { | 35 | + result.push_back(tensor.clone()); |
| 36 | - result.push_back(tensor.clone()); | 36 | + } |
| 37 | - } | 37 | + at::TensorList result_ = at::TensorList(result); |
| 38 | - at::TensorList result_ = at::TensorList(result); | ||
| 39 | 38 | ||
| 40 | - EXEC_NPU_CMD(aclnnScatterList, result_, indice, updates, mask, reduce_ptr, axis); | 39 | + EXEC_NPU_CMD(aclnnScatterList, result_, indice, updates, mask, reduce_ptr, axis); |
| 41 | - | ||
| 42 | - return result; | ||
| 43 | - } | ||
| 44 | - | ||
| 45 | - void npu_scatter_list_( | ||
| 46 | - at::TensorList self, | ||
| 47 | - const at::Tensor &indice, | ||
| 48 | - const at::Tensor &updates, | ||
| 49 | - const c10::optional<at::Tensor> &mask, | ||
| 50 | - c10::string_view reduce, | ||
| 51 | - int64_t axis) | ||
| 52 | - { | ||
| 53 | - std::string reduce_str = std::string(reduce); | ||
| 54 | - char *reduce_ptr = const_cast<char *>(reduce_str.c_str()); | ||
| 55 | - EXEC_NPU_CMD(aclnnScatterList, self, indice, updates, mask, reduce_ptr, axis); | ||
| 56 | - return; | ||
| 57 | - } | ||
| 58 | 40 | ||
| 41 | + return result; | ||
| 59 | } | 42 | } |
| 43 | + | ||
| 44 | +void npu_scatter_list_( | ||
| 45 | + at::TensorList self, | ||
| 46 | + const at::Tensor& indice, | ||
| 47 | + const at::Tensor& updates, | ||
| 48 | + const c10::optional<at::Tensor>& mask, | ||
| 49 | + c10::string_view reduce, | ||
| 50 | + int64_t axis) { | ||
| 51 | + std::string reduce_str = std::string(reduce); | ||
| 52 | + char* reduce_ptr = const_cast<char*>(reduce_str.c_str()); | ||
| 53 | + EXEC_NPU_CMD(aclnnScatterList, self, indice, updates, mask, reduce_ptr, axis); | ||
| 54 | + return; | ||
| 55 | +} | ||
| 56 | + | ||
| 57 | +} // namespace op_api | ||
| @@ -18,25 +18,17 @@ | |||
| 18 | 18 | ||
| 19 | 19 | ||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | - using npu_preparation = at_npu::native::OpPreparation; | 21 | +using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -at::Tensor npu_scatter_nd_update( | 23 | +at::Tensor npu_scatter_nd_update(const at::Tensor& self, const at::Tensor& indices, const at::Tensor& updates) { |
| 24 | - const at::Tensor &self, | 24 | + at::Tensor result = self.clone(); |
| 25 | - const at::Tensor &indices, | 25 | + EXEC_NPU_CMD(aclnnScatterNdUpdate, result, indices, updates); |
| 26 | - const at::Tensor &updates) | 26 | + return result; |
| 27 | -{ | ||
| 28 | - at::Tensor result = self.clone(); | ||
| 29 | - EXEC_NPU_CMD(aclnnScatterNdUpdate, result, indices, updates); | ||
| 30 | - return result; | ||
| 31 | } | 27 | } |
| 32 | 28 | ||
| 33 | -at::Tensor &npu_scatter_nd_update_( | 29 | +at::Tensor& npu_scatter_nd_update_(at::Tensor& self, const at::Tensor& indices, const at::Tensor& updates) { |
| 34 | - at::Tensor &self, | 30 | + EXEC_NPU_CMD(aclnnScatterNdUpdate, self, indices, updates); |
| 35 | - const at::Tensor &indices, | 31 | + return self; |
| 36 | - const at::Tensor &updates) | ||
| 37 | -{ | ||
| 38 | - EXEC_NPU_CMD(aclnnScatterNdUpdate, self, indices, updates); | ||
| 39 | - return self; | ||
| 40 | } | 32 | } |
| 41 | 33 | ||
| 42 | -} | 34 | +} // namespace op_api |
| @@ -29,19 +29,30 @@ std::tuple<at::Tensor, at::Tensor> npu_scatter_pa_kv_cache_functional( | |||
| 29 | const c10::optional<at::Tensor>& compress_lens, | 29 | const c10::optional<at::Tensor>& compress_lens, |
| 30 | const c10::optional<at::Tensor>& compress_seq_offsets, | 30 | const c10::optional<at::Tensor>& compress_seq_offsets, |
| 31 | const c10::optional<at::Tensor>& seq_lens, | 31 | const c10::optional<at::Tensor>& seq_lens, |
| 32 | - c10::optional<c10::string_view> cache_mode) | 32 | + c10::optional<c10::string_view> cache_mode) { |
| 33 | -{ | 33 | + char* cache_mode_ptr = cache_mode.has_value() ? const_cast<char*>(cache_mode.value().data()) : nullptr; |
| 34 | - char* cache_mode_ptr = cache_mode.has_value() ? const_cast<char *>(cache_mode.value().data()) : nullptr; | 34 | + char* scatter_mode = "None"; |
| 35 | - char* scatter_mode = "None"; | 35 | + c10::SmallVector<int64_t, op_infer::SIZE> strides_size = {1, 1}; |
| 36 | - c10::SmallVector<int64_t, op_infer::SIZE> strides_size = {1, 1}; | 36 | + at::IntArrayRef strides = at::IntArrayRef(strides_size); |
| 37 | - at::IntArrayRef strides = at::IntArrayRef(strides_size); | 37 | + c10::SmallVector<int64_t, op_infer::SIZE> offsets_size = {0, 0}; |
| 38 | - c10::SmallVector<int64_t, op_infer::SIZE> offsets_size = {0, 0}; | 38 | + at::IntArrayRef offsets = at::IntArrayRef(offsets_size); |
| 39 | - at::IntArrayRef offsets = at::IntArrayRef(offsets_size); | 39 | + auto keyCacheClone = key_cache.clone(at::MemoryFormat::Contiguous); |
| 40 | - auto keyCacheClone = key_cache.clone(at::MemoryFormat::Contiguous); | 40 | + auto valueCacheClone = value_cache.clone(at::MemoryFormat::Contiguous); |
| 41 | - auto valueCacheClone = value_cache.clone(at::MemoryFormat::Contiguous); | 41 | + EXEC_NPU_NO_FORMAT_CHECK_CMD( |
| 42 | - EXEC_NPU_NO_FORMAT_CHECK_CMD(aclnnScatterPaKvCache, key, keyCacheClone, slot_mapping, value, | 42 | + aclnnScatterPaKvCache, |
| 43 | - valueCacheClone, compress_lens, compress_seq_offsets, seq_lens, cache_mode_ptr, scatter_mode, strides, offsets); | 43 | + key, |
| 44 | - return std::make_tuple(keyCacheClone, valueCacheClone); | 44 | + keyCacheClone, |
| 45 | + slot_mapping, | ||
| 46 | + value, | ||
| 47 | + valueCacheClone, | ||
| 48 | + compress_lens, | ||
| 49 | + compress_seq_offsets, | ||
| 50 | + seq_lens, | ||
| 51 | + cache_mode_ptr, | ||
| 52 | + scatter_mode, | ||
| 53 | + strides, | ||
| 54 | + offsets); | ||
| 55 | + return std::make_tuple(keyCacheClone, valueCacheClone); | ||
| 45 | } | 56 | } |
| 46 | 57 | ||
| 47 | void npu_scatter_pa_kv_cache( | 58 | void npu_scatter_pa_kv_cache( |
| @@ -53,17 +64,28 @@ void npu_scatter_pa_kv_cache( | |||
| 53 | const c10::optional<at::Tensor>& compress_lens, | 64 | const c10::optional<at::Tensor>& compress_lens, |
| 54 | const c10::optional<at::Tensor>& compress_seq_offsets, | 65 | const c10::optional<at::Tensor>& compress_seq_offsets, |
| 55 | const c10::optional<at::Tensor>& seq_lens, | 66 | const c10::optional<at::Tensor>& seq_lens, |
| 56 | - c10::optional<c10::string_view> cache_mode) | 67 | + c10::optional<c10::string_view> cache_mode) { |
| 57 | -{ | 68 | + char* cache_mode_ptr = cache_mode.has_value() ? const_cast<char*>(cache_mode.value().data()) : nullptr; |
| 58 | - char* cache_mode_ptr = cache_mode.has_value() ? const_cast<char *>(cache_mode.value().data()) : nullptr; | 69 | + char* scatter_mode = "None"; |
| 59 | - char* scatter_mode = "None"; | 70 | + c10::SmallVector<int64_t, op_infer::SIZE> strides_size = {1, 1}; |
| 60 | - c10::SmallVector<int64_t, op_infer::SIZE> strides_size = {1, 1}; | 71 | + at::IntArrayRef strides = at::IntArrayRef(strides_size); |
| 61 | - at::IntArrayRef strides = at::IntArrayRef(strides_size); | 72 | + c10::SmallVector<int64_t, op_infer::SIZE> offsets_size = {0, 0}; |
| 62 | - c10::SmallVector<int64_t, op_infer::SIZE> offsets_size = {0, 0}; | 73 | + at::IntArrayRef offsets = at::IntArrayRef(offsets_size); |
| 63 | - at::IntArrayRef offsets = at::IntArrayRef(offsets_size); | ||
| 64 | 74 | ||
| 65 | - EXEC_NPU_NO_FORMAT_CHECK_CMD(aclnnScatterPaKvCache, key, key_cache, slot_mapping, value, value_cache, | 75 | + EXEC_NPU_NO_FORMAT_CHECK_CMD( |
| 66 | - compress_lens, compress_seq_offsets, seq_lens, cache_mode_ptr, scatter_mode, strides, offsets); | 76 | + aclnnScatterPaKvCache, |
| 77 | + key, | ||
| 78 | + key_cache, | ||
| 79 | + slot_mapping, | ||
| 80 | + value, | ||
| 81 | + value_cache, | ||
| 82 | + compress_lens, | ||
| 83 | + compress_seq_offsets, | ||
| 84 | + seq_lens, | ||
| 85 | + cache_mode_ptr, | ||
| 86 | + scatter_mode, | ||
| 87 | + strides, | ||
| 88 | + offsets); | ||
| 67 | } | 89 | } |
| 68 | 90 | ||
| 69 | -} | 91 | +} // namespace op_api |
| @@ -23,12 +23,12 @@ namespace op_api { | |||
| 23 | using npu_preparation = at_npu::native::OpPreparation; | 23 | using npu_preparation = at_npu::native::OpPreparation; |
| 24 | namespace { | 24 | namespace { |
| 25 | enum class ScatterReduceType : int64_t { | 25 | enum class ScatterReduceType : int64_t { |
| 26 | - REDUCE_NONE = 0, | 26 | + REDUCE_NONE = 0, |
| 27 | - REDUCE_ADD = 1, | 27 | + REDUCE_ADD = 1, |
| 28 | - REDUCE_MUL = 2, | 28 | + REDUCE_MUL = 2, |
| 29 | - REDUCE_MAX = 3, | 29 | + REDUCE_MAX = 3, |
| 30 | - REDUCE_MIN = 4, | 30 | + REDUCE_MIN = 4, |
| 31 | - REDUCE_MEAN = 5, | 31 | + REDUCE_MEAN = 5, |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | const std::pair<c10::string_view, ScatterReduceType> REDUCE_TYPE_MAP[] = { | 34 | const std::pair<c10::string_view, ScatterReduceType> REDUCE_TYPE_MAP[] = { |
| @@ -44,17 +44,18 @@ const std::pair<c10::string_view, ScatterReduceType> REDUCE_TYPE_MAP[] = { | |||
| 44 | {"mean", ScatterReduceType::REDUCE_MEAN}, | 44 | {"mean", ScatterReduceType::REDUCE_MEAN}, |
| 45 | }; | 45 | }; |
| 46 | 46 | ||
| 47 | -int64_t get_reduce(c10::string_view reduce, const char* op_name) | 47 | +int64_t get_reduce(c10::string_view reduce, const char* op_name) { |
| 48 | -{ | 48 | + for (const auto& reduce_pair : REDUCE_TYPE_MAP) { |
| 49 | - for (const auto& reduce_pair : REDUCE_TYPE_MAP) { | 49 | + if (reduce == reduce_pair.first) { |
| 50 | - if (reduce == reduce_pair.first) { | 50 | + return static_cast<int64_t>(reduce_pair.second); |
| 51 | - return static_cast<int64_t>(reduce_pair.second); | ||
| 52 | - } | ||
| 53 | } | 51 | } |
| 54 | - TORCH_CHECK( | 52 | + } |
| 55 | - false, op_name, | 53 | + TORCH_CHECK( |
| 56 | - ": expected reduce to be one of none, sum, add, amin, min, amax, max, mul, prod or mean, but got ", reduce, | 54 | + false, |
| 57 | - OPS_ERROR(ErrCode::PARAM)); | 55 | + op_name, |
| 56 | + ": expected reduce to be one of none, sum, add, amin, min, amax, max, mul, prod or mean, but got ", | ||
| 57 | + reduce, | ||
| 58 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 58 | } | 59 | } |
| 59 | 60 | ||
| 60 | at::Tensor scatter_reduce_cpu_fallback( | 61 | at::Tensor scatter_reduce_cpu_fallback( |
| @@ -63,12 +64,11 @@ at::Tensor scatter_reduce_cpu_fallback( | |||
| 63 | const at::Tensor& index, | 64 | const at::Tensor& index, |
| 64 | const at::Tensor& src, | 65 | const at::Tensor& src, |
| 65 | c10::string_view reduce, | 66 | c10::string_view reduce, |
| 66 | - bool include_self) | 67 | + bool include_self) { |
| 67 | -{ | 68 | + at::Tensor self_cpu = self.cpu(); |
| 68 | - at::Tensor self_cpu = self.cpu(); | 69 | + at::Tensor index_cpu = index.cpu(); |
| 69 | - at::Tensor index_cpu = index.cpu(); | 70 | + at::Tensor src_cpu = src.cpu(); |
| 70 | - at::Tensor src_cpu = src.cpu(); | 71 | + return at::scatter_reduce(self_cpu, dim, index_cpu, src_cpu, reduce, include_self).to(self.options()); |
| 71 | - return at::scatter_reduce(self_cpu, dim, index_cpu, src_cpu, reduce, include_self).to(self.options()); | ||
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | at::Tensor& scatter_reduce_out_cpu_fallback( | 74 | at::Tensor& scatter_reduce_out_cpu_fallback( |
| @@ -78,15 +78,14 @@ at::Tensor& scatter_reduce_out_cpu_fallback( | |||
| 78 | const at::Tensor& src, | 78 | const at::Tensor& src, |
| 79 | c10::string_view reduce, | 79 | c10::string_view reduce, |
| 80 | bool include_self, | 80 | bool include_self, |
| 81 | - at::Tensor& out) | 81 | + at::Tensor& out) { |
| 82 | -{ | 82 | + at::Tensor self_cpu = self.cpu(); |
| 83 | - at::Tensor self_cpu = self.cpu(); | 83 | + at::Tensor index_cpu = index.cpu(); |
| 84 | - at::Tensor index_cpu = index.cpu(); | 84 | + at::Tensor src_cpu = src.cpu(); |
| 85 | - at::Tensor src_cpu = src.cpu(); | 85 | + at::Tensor out_cpu = out.cpu(); |
| 86 | - at::Tensor out_cpu = out.cpu(); | 86 | + at::scatter_reduce_out(out_cpu, self_cpu, dim, index_cpu, src_cpu, reduce, include_self); |
| 87 | - at::scatter_reduce_out(out_cpu, self_cpu, dim, index_cpu, src_cpu, reduce, include_self); | 87 | + out.copy_(out_cpu); |
| 88 | - out.copy_(out_cpu); | 88 | + return out; |
| 89 | - return out; | ||
| 90 | } | 89 | } |
| 91 | 90 | ||
| 92 | at::Tensor& scatter_reduce_inplace_cpu_fallback( | 91 | at::Tensor& scatter_reduce_inplace_cpu_fallback( |
| @@ -95,14 +94,13 @@ at::Tensor& scatter_reduce_inplace_cpu_fallback( | |||
| 95 | const at::Tensor& index, | 94 | const at::Tensor& index, |
| 96 | const at::Tensor& src, | 95 | const at::Tensor& src, |
| 97 | c10::string_view reduce, | 96 | c10::string_view reduce, |
| 98 | - bool include_self) | 97 | + bool include_self) { |
| 99 | -{ | 98 | + at::Tensor self_cpu = self.cpu(); |
| 100 | - at::Tensor self_cpu = self.cpu(); | 99 | + at::Tensor index_cpu = index.cpu(); |
| 101 | - at::Tensor index_cpu = index.cpu(); | 100 | + at::Tensor src_cpu = src.cpu(); |
| 102 | - at::Tensor src_cpu = src.cpu(); | 101 | + self_cpu.scatter_reduce_(dim, index_cpu, src_cpu, reduce, include_self); |
| 103 | - self_cpu.scatter_reduce_(dim, index_cpu, src_cpu, reduce, include_self); | 102 | + self.copy_(self_cpu); |
| 104 | - self.copy_(self_cpu); | 103 | + return self; |
| 105 | - return self; | ||
| 106 | } | 104 | } |
| 107 | } // namespace | 105 | } // namespace |
| 108 | 106 | ||
| @@ -112,23 +110,19 @@ at::Tensor scatter_reduce( | |||
| 112 | const at::Tensor& index, | 110 | const at::Tensor& index, |
| 113 | const at::Tensor& src, | 111 | const at::Tensor& src, |
| 114 | c10::string_view reduce, | 112 | c10::string_view reduce, |
| 115 | - bool include_self) | 113 | + bool include_self) { |
| 116 | -{ | 114 | + if (include_self && (reduce == "sum" || reduce == "add") && |
| 117 | - if (include_self && (reduce == "sum" || reduce == "add") && | 115 | + c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950 && self.scalar_type() == at::kFloat) { |
| 118 | - c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950 && | 116 | + DO_COMPATIBILITY_COMMON( |
| 119 | - self.scalar_type() == at::kFloat) { | 117 | + aclnnScatterReduce, scatter_reduce_cpu_fallback(self, dim, index, src, reduce, include_self)); |
| 120 | - DO_COMPATIBILITY_COMMON( | 118 | + auto result = self.clone(at::MemoryFormat::Contiguous); |
| 121 | - aclnnScatterReduce, | 119 | + npu_preparation::CheckMemory({result, index, src}, {result}); |
| 122 | - scatter_reduce_cpu_fallback(self, dim, index, src, reduce, include_self) | 120 | + int64_t reduction = get_reduce(reduce, "scatter_reduce()"); |
| 123 | - ); | 121 | + EXEC_NPU_CMD(aclnnScatterReduce, result, dim, index, src, reduction, include_self, result); |
| 124 | - auto result = self.clone(at::MemoryFormat::Contiguous); | 122 | + return result; |
| 125 | - npu_preparation::CheckMemory({result, index, src}, {result}); | 123 | + } |
| 126 | - int64_t reduction = get_reduce(reduce, "scatter_reduce()"); | ||
| 127 | - EXEC_NPU_CMD(aclnnScatterReduce, result, dim, index, src, reduction, include_self, result); | ||
| 128 | - return result; | ||
| 129 | - } | ||
| 130 | 124 | ||
| 131 | - return scatter_reduce_cpu_fallback(self, dim, index, src, reduce, include_self); | 125 | + return scatter_reduce_cpu_fallback(self, dim, index, src, reduce, include_self); |
| 132 | } | 126 | } |
| 133 | 127 | ||
| 134 | at::Tensor& scatter_reduce_out( | 128 | at::Tensor& scatter_reduce_out( |
| @@ -138,14 +132,13 @@ at::Tensor& scatter_reduce_out( | |||
| 138 | const at::Tensor& src, | 132 | const at::Tensor& src, |
| 139 | c10::string_view reduce, | 133 | c10::string_view reduce, |
| 140 | bool include_self, | 134 | bool include_self, |
| 141 | - at::Tensor& out) | 135 | + at::Tensor& out) { |
| 142 | -{ | 136 | + DO_COMPATIBILITY_COMMON( |
| 143 | - DO_COMPATIBILITY_COMMON( | 137 | + aclnnScatterReduce, scatter_reduce_out_cpu_fallback(self, dim, index, src, reduce, include_self, out)); |
| 144 | - aclnnScatterReduce, scatter_reduce_out_cpu_fallback(self, dim, index, src, reduce, include_self, out)); | 138 | + npu_preparation::CheckMemory({self, index, src}, {out}); |
| 145 | - npu_preparation::CheckMemory({self, index, src}, {out}); | 139 | + int64_t reduction = get_reduce(reduce, "scatter_reduce_out()"); |
| 146 | - int64_t reduction = get_reduce(reduce, "scatter_reduce_out()"); | 140 | + EXEC_NPU_CMD(aclnnScatterReduce, self, dim, index, src, reduction, include_self, out); |
| 147 | - EXEC_NPU_CMD(aclnnScatterReduce, self, dim, index, src, reduction, include_self, out); | 141 | + return out; |
| 148 | - return out; | ||
| 149 | } | 142 | } |
| 150 | 143 | ||
| 151 | at::Tensor& scatter_reduce_( | 144 | at::Tensor& scatter_reduce_( |
| @@ -154,20 +147,16 @@ at::Tensor& scatter_reduce_( | |||
| 154 | const at::Tensor& index, | 147 | const at::Tensor& index, |
| 155 | const at::Tensor& src, | 148 | const at::Tensor& src, |
| 156 | c10::string_view reduce, | 149 | c10::string_view reduce, |
| 157 | - bool include_self) | 150 | + bool include_self) { |
| 158 | -{ | 151 | + if (include_self && (reduce == "sum" || reduce == "add") && |
| 159 | - if (include_self && (reduce == "sum" || reduce == "add") && | 152 | + c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950 && self.scalar_type() == at::kFloat) { |
| 160 | - c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950 && | 153 | + DO_COMPATIBILITY_COMMON( |
| 161 | - self.scalar_type() == at::kFloat) { | 154 | + aclnnInplaceScatterReduce, scatter_reduce_inplace_cpu_fallback(self, dim, index, src, reduce, include_self)); |
| 162 | - DO_COMPATIBILITY_COMMON( | 155 | + npu_preparation::CheckMemory({self, index, src}, {self}); |
| 163 | - aclnnInplaceScatterReduce, | 156 | + int64_t reduction = get_reduce(reduce, "scatter_reduce_()"); |
| 164 | - scatter_reduce_inplace_cpu_fallback(self, dim, index, src, reduce, include_self) | 157 | + EXEC_NPU_CMD(aclnnInplaceScatterReduce, self, dim, index, src, reduction, include_self); |
| 165 | - ); | 158 | + return self; |
| 166 | - npu_preparation::CheckMemory({self, index, src}, {self}); | 159 | + } |
| 167 | - int64_t reduction = get_reduce(reduce, "scatter_reduce_()"); | 160 | + return scatter_reduce_inplace_cpu_fallback(self, dim, index, src, reduce, include_self); |
| 168 | - EXEC_NPU_CMD(aclnnInplaceScatterReduce, self, dim, index, src, reduction, include_self); | ||
| 169 | - return self; | ||
| 170 | - } | ||
| 171 | - return scatter_reduce_inplace_cpu_fallback(self, dim, index, src, reduce, include_self); | ||
| 172 | -} | ||
| 173 | } | 161 | } |
| 162 | +} // namespace op_api | ||
| @@ -17,26 +17,16 @@ | |||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | namespace op_api { | 19 | namespace op_api { |
| 20 | -at::Tensor scatter_update( | 20 | +at::Tensor scatter_update(const at::Tensor& self, const at::Tensor& indices, const at::Tensor& updates, int64_t axis) { |
| 21 | - const at::Tensor &self, | 21 | + // The attribute 'reduce' of Scatter only supports setting it to 'update'. |
| 22 | - const at::Tensor &indices, | 22 | + at::Tensor result = self.clone(); |
| 23 | - const at::Tensor &updates, | 23 | + EXEC_NPU_CMD(aclnnInplaceScatterUpdate, result, indices, updates, axis); |
| 24 | - int64_t axis) | 24 | + return result; |
| 25 | -{ | ||
| 26 | - // The attribute 'reduce' of Scatter only supports setting it to 'update'. | ||
| 27 | - at::Tensor result = self.clone(); | ||
| 28 | - EXEC_NPU_CMD(aclnnInplaceScatterUpdate, result, indices, updates, axis); | ||
| 29 | - return result; | ||
| 30 | } | 25 | } |
| 31 | 26 | ||
| 32 | -at::Tensor &scatter_update_( | 27 | +at::Tensor& scatter_update_(at::Tensor& self, const at::Tensor& indices, const at::Tensor& updates, int64_t axis) { |
| 33 | - at::Tensor &self, | 28 | + // The attribute 'reduce' of Scatter only supports setting it to 'update'. |
| 34 | - const at::Tensor &indices, | 29 | + EXEC_NPU_CMD(aclnnInplaceScatterUpdate, self, indices, updates, axis); |
| 35 | - const at::Tensor &updates, | 30 | + return self; |
| 36 | - int64_t axis) | ||
| 37 | -{ | ||
| 38 | - // The attribute 'reduce' of Scatter only supports setting it to 'update'. | ||
| 39 | - EXEC_NPU_CMD(aclnnInplaceScatterUpdate, self, indices, updates, axis); | ||
| 40 | - return self; | ||
| 41 | } | 31 | } |
| 42 | -} // namespace op_api | 32 | +} // namespace op_api |
| @@ -20,22 +20,20 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -at::Tensor &sgn_out(const at::Tensor &self, at::Tensor &result) | 23 | +at::Tensor& sgn_out(const at::Tensor& self, at::Tensor& result) { |
| 24 | -{ | ||
| 25 | DO_COMPATIBILITY(aclnnSign, acl_op::sgn_out(self, result)); | 24 | DO_COMPATIBILITY(aclnnSign, acl_op::sgn_out(self, result)); |
| 26 | npu_preparation::check_tensor({self}, result, self); | 25 | npu_preparation::check_tensor({self}, result, self); |
| 27 | EXEC_NPU_CMD(aclnnSign, self, result); | 26 | EXEC_NPU_CMD(aclnnSign, self, result); |
| 28 | return result; | 27 | return result; |
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | -at::Tensor sgn(const at::Tensor &self) | 30 | +at::Tensor sgn(const at::Tensor& self) { |
| 32 | -{ | 31 | + DO_COMPATIBILITY(aclnnSign, acl_op::sgn(self)); |
| 33 | - DO_COMPATIBILITY(aclnnSign, acl_op::sgn(self)); | 32 | + auto outputSize = op_infer::input_same_output_size(self); |
| 34 | - auto outputSize = op_infer::input_same_output_size(self); | 33 | + at::Tensor result = npu_preparation::apply_tensor_without_format(outputSize, self.options()); |
| 35 | - at::Tensor result = npu_preparation::apply_tensor_without_format(outputSize, self.options()); | 34 | + EXEC_NPU_CMD(aclnnSign, self, result); |
| 36 | - EXEC_NPU_CMD(aclnnSign, self, result); | 35 | + at::namedinference::propagate_names(result, self); |
| 37 | - at::namedinference::propagate_names(result, self); | 36 | + return result; |
| 38 | - return result; | ||
| 39 | } | 37 | } |
| 40 | 38 | ||
| 41 | -} | 39 | +} // namespace op_api |
| @@ -20,45 +20,42 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -at::Tensor aclnnNotFound(const at::Tensor &val) | 23 | +at::Tensor aclnnNotFound(const at::Tensor& val) { |
| 24 | -{ | 24 | + TORCH_CHECK(false, "aclnnSilentCheck not found. " + OPS_ERROR(ErrCode::INTERNAL)); |
| 25 | - TORCH_CHECK(false, "aclnnSilentCheck not found. " + OPS_ERROR(ErrCode::INTERNAL)); | 25 | + return val; |
| 26 | - return val; | ||
| 27 | } | 26 | } |
| 28 | 27 | ||
| 29 | at::Tensor _npu_silent_check_v2( | 28 | at::Tensor _npu_silent_check_v2( |
| 30 | - const at::Tensor &val, | 29 | + const at::Tensor& val, |
| 31 | - at::Tensor &input_grad, | 30 | + at::Tensor& input_grad, |
| 32 | - at::Tensor &sfda, | 31 | + at::Tensor& sfda, |
| 33 | - at::Tensor &step, | 32 | + at::Tensor& step, |
| 34 | int64_t c_min_steps, | 33 | int64_t c_min_steps, |
| 35 | double c_thresh_l1, | 34 | double c_thresh_l1, |
| 36 | double c_coeff_l1, | 35 | double c_coeff_l1, |
| 37 | double c_thresh_l2, | 36 | double c_thresh_l2, |
| 38 | double c_coeff_l2, | 37 | double c_coeff_l2, |
| 39 | - int64_t npu_asd_detect) | 38 | + int64_t npu_asd_detect) { |
| 40 | -{ | 39 | + DO_COMPATIBILITY(aclnnSilentCheck, aclnnNotFound(val)); |
| 41 | - DO_COMPATIBILITY(aclnnSilentCheck, aclnnNotFound(val)); | 40 | + at::Tensor result = npu_preparation::apply_tensor_without_format(step.sizes(), step.options().dtype(at::kInt)); |
| 42 | - at::Tensor result = npu_preparation::apply_tensor_without_format(step.sizes(), step.options().dtype(at::kInt)); | 41 | + int32_t c_min_steps_cast = static_cast<int32_t>(c_min_steps); |
| 43 | - int32_t c_min_steps_cast = static_cast<int32_t>(c_min_steps); | 42 | + float c_thresh_l1_cast = static_cast<float>(c_thresh_l1); |
| 44 | - float c_thresh_l1_cast = static_cast<float>(c_thresh_l1); | 43 | + float c_coeff_l1_cast = static_cast<float>(c_coeff_l1); |
| 45 | - float c_coeff_l1_cast = static_cast<float>(c_coeff_l1); | 44 | + float c_thresh_l2_cast = static_cast<float>(c_thresh_l2); |
| 46 | - float c_thresh_l2_cast = static_cast<float>(c_thresh_l2); | 45 | + float c_coeff_l2_cast = static_cast<float>(c_coeff_l2); |
| 47 | - float c_coeff_l2_cast = static_cast<float>(c_coeff_l2); | 46 | + EXEC_NPU_CMD( |
| 48 | - EXEC_NPU_CMD( | 47 | + aclnnSilentCheck, |
| 49 | - aclnnSilentCheck, | 48 | + val, |
| 50 | - val, | 49 | + input_grad, |
| 51 | - input_grad, | 50 | + sfda, |
| 52 | - sfda, | 51 | + step, |
| 53 | - step, | 52 | + c_min_steps_cast, |
| 54 | - c_min_steps_cast, | 53 | + c_thresh_l1_cast, |
| 55 | - c_thresh_l1_cast, | 54 | + c_coeff_l1_cast, |
| 56 | - c_coeff_l1_cast, | 55 | + c_thresh_l2_cast, |
| 57 | - c_thresh_l2_cast, | 56 | + c_coeff_l2_cast, |
| 58 | - c_coeff_l2_cast, | 57 | + npu_asd_detect, |
| 59 | - npu_asd_detect, | 58 | + result); |
| 60 | - result); | 59 | + return result; |
| 61 | - return result; | ||
| 62 | } | 60 | } |
| 63 | } // namespace op_api | 61 | } // namespace op_api |
| 64 | - | ||
| @@ -20,35 +20,45 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -at::Tensor aclnnNotFoundV2(const at::Tensor &val) | 23 | +at::Tensor aclnnNotFoundV2(const at::Tensor& val) { |
| 24 | -{ | 24 | + TORCH_CHECK(false, "aclnnSilentCheckV2 not found. " + OPS_ERROR(ErrCode::INTERNAL)); |
| 25 | - TORCH_CHECK(false, "aclnnSilentCheckV2 not found. " + OPS_ERROR(ErrCode::INTERNAL)); | 25 | + return val; |
| 26 | - return val; | ||
| 27 | } | 26 | } |
| 28 | 27 | ||
| 29 | at::Tensor _npu_silent_check_v3( | 28 | at::Tensor _npu_silent_check_v3( |
| 30 | - const at::Tensor &val, | 29 | + const at::Tensor& val, |
| 31 | - at::Tensor &input_grad, | 30 | + at::Tensor& input_grad, |
| 32 | - at::Tensor &step, | 31 | + at::Tensor& step, |
| 33 | - at::Tensor &max, | 32 | + at::Tensor& max, |
| 34 | - at::Tensor &avg, | 33 | + at::Tensor& avg, |
| 35 | double c_thresh_l1, | 34 | double c_thresh_l1, |
| 36 | double c_thresh_l2, | 35 | double c_thresh_l2, |
| 37 | double beta1, | 36 | double beta1, |
| 38 | - int64_t npu_asd_detect) | 37 | + int64_t npu_asd_detect) { |
| 39 | -{ | 38 | + DO_COMPATIBILITY(aclnnSilentCheckV2, aclnnNotFoundV2(val)); |
| 40 | - DO_COMPATIBILITY(aclnnSilentCheckV2, aclnnNotFoundV2(val)); | 39 | + at::Tensor result = npu_preparation::apply_tensor_without_format(step.sizes(), step.options().dtype(at::kInt)); |
| 41 | - at::Tensor result = npu_preparation::apply_tensor_without_format(step.sizes(), step.options().dtype(at::kInt)); | 40 | + float c_thresh_l1_cast = static_cast<float>(c_thresh_l1); |
| 42 | - float c_thresh_l1_cast = static_cast<float>(c_thresh_l1); | 41 | + float c_thresh_l2_cast = static_cast<float>(c_thresh_l2); |
| 43 | - float c_thresh_l2_cast = static_cast<float>(c_thresh_l2); | 42 | + float beta1_cast = static_cast<float>(beta1); |
| 44 | - float beta1_cast = static_cast<float>(beta1); | 43 | + auto dst_size = input_grad.sizes(); |
| 45 | - auto dst_size = input_grad.sizes(); | 44 | + auto dst_stride = input_grad.strides(); |
| 46 | - auto dst_stride = input_grad.strides(); | 45 | + c10::SmallVector<int64_t, N> offset = {input_grad.storage_offset()}; |
| 47 | - c10::SmallVector<int64_t, N> offset = {input_grad.storage_offset()}; | 46 | + auto dst_offset = at::IntArrayRef(offset); |
| 48 | - auto dst_offset = at::IntArrayRef(offset); | 47 | + EXEC_NPU_CMD( |
| 49 | - EXEC_NPU_CMD(aclnnSilentCheckV2, val, max, avg, input_grad, step, dst_size, dst_stride, dst_offset, | 48 | + aclnnSilentCheckV2, |
| 50 | - c_thresh_l1_cast, c_thresh_l2_cast, beta1_cast, npu_asd_detect, result); | 49 | + val, |
| 51 | - return result; | 50 | + max, |
| 51 | + avg, | ||
| 52 | + input_grad, | ||
| 53 | + step, | ||
| 54 | + dst_size, | ||
| 55 | + dst_stride, | ||
| 56 | + dst_offset, | ||
| 57 | + c_thresh_l1_cast, | ||
| 58 | + c_thresh_l2_cast, | ||
| 59 | + beta1_cast, | ||
| 60 | + npu_asd_detect, | ||
| 61 | + result); | ||
| 62 | + return result; | ||
| 52 | } | 63 | } |
| 53 | } // namespace op_api | 64 | } // namespace op_api |
| 54 | - | ||
| @@ -20,32 +20,31 @@ | |||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | namespace op_api { | 22 | namespace op_api { |
| 23 | -at::Tensor& silu_backward_out(const at::Tensor& grad_output, const at::Tensor& self, at::Tensor& result) | 23 | +at::Tensor& silu_backward_out(const at::Tensor& grad_output, const at::Tensor& self, at::Tensor& result) { |
| 24 | -{ | 24 | + DO_COMPATIBILITY(aclnnSiluBackward, acl_op::silu_backward_out(grad_output, self, result)); |
| 25 | - DO_COMPATIBILITY(aclnnSiluBackward, acl_op::silu_backward_out(grad_output, self, result)); | 25 | + if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { |
| 26 | - if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { | 26 | + at_npu::native::OpPreparation::check_tensor({grad_output, self}, result, grad_output); |
| 27 | - at_npu::native::OpPreparation::check_tensor({grad_output, self}, result, grad_output); | 27 | + } |
| 28 | - } | 28 | + EXEC_NPU_CMD(aclnnSiluBackward, grad_output, self, result); |
| 29 | - EXEC_NPU_CMD(aclnnSiluBackward, grad_output, self, result); | 29 | + return result; |
| 30 | - return result; | ||
| 31 | } | 30 | } |
| 32 | 31 | ||
| 33 | -at::Tensor silu_backward(const at::Tensor& grad_output, const at::Tensor& self) | 32 | +at::Tensor silu_backward(const at::Tensor& grad_output, const at::Tensor& self) { |
| 34 | -{ | 33 | + DO_COMPATIBILITY(aclnnSiluBackward, acl_op::silu_backward(grad_output, self)); |
| 35 | - DO_COMPATIBILITY(aclnnSiluBackward, acl_op::silu_backward(grad_output, self)); | 34 | + at::Tensor grad_input; |
| 36 | - at::Tensor grad_input; | 35 | + if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { |
| 37 | - if (c10_npu::GetSocVersion() < c10_npu::SocVersion::Ascend950) { | 36 | + grad_input = at_npu::native::OpPreparation::apply_tensor_without_format(grad_output); |
| 38 | - grad_input = at_npu::native::OpPreparation::apply_tensor_without_format(grad_output); | 37 | + } else { |
| 39 | - } else { | 38 | + at::ScalarType output_dtype = grad_output.scalar_type(); |
| 40 | - at::ScalarType output_dtype = grad_output.scalar_type(); | 39 | + if (grad_output.scalar_type() != self.scalar_type()) { |
| 41 | - if (grad_output.scalar_type() != self.scalar_type()) { | 40 | + output_dtype = at::kFloat; |
| 42 | - output_dtype = at::kFloat; | ||
| 43 | - } | ||
| 44 | - auto output_size = op_infer::broadcast_ops_npu_output_size(grad_output, self); | ||
| 45 | - grad_input = at_npu::native::OpPreparation::apply_tensor_without_format(output_size, self.options().dtype(output_dtype)); | ||
| 46 | } | 41 | } |
| 47 | - EXEC_NPU_CMD(aclnnSiluBackward, grad_output, self, grad_input); | 42 | + auto output_size = op_infer::broadcast_ops_npu_output_size(grad_output, self); |
| 48 | - return grad_input; | 43 | + grad_input = |
| 44 | + at_npu::native::OpPreparation::apply_tensor_without_format(output_size, self.options().dtype(output_dtype)); | ||
| 45 | + } | ||
| 46 | + EXEC_NPU_CMD(aclnnSiluBackward, grad_output, self, grad_input); | ||
| 47 | + return grad_input; | ||
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | -} | 50 | +} // namespace op_api |
| @@ -20,26 +20,26 @@ | |||
| 20 | 20 | ||
| 21 | namespace op_api { | 21 | namespace op_api { |
| 22 | 22 | ||
| 23 | -at::Tensor& npu_sim_exponential_(at::Tensor& self, double lambd, c10::optional<at::Generator> generator) | 23 | +at::Tensor& npu_sim_exponential_(at::Tensor& self, double lambd, c10::optional<at::Generator> generator) { |
| 24 | -{ | 24 | + TORCH_CHECK( |
| 25 | - TORCH_CHECK(lambd > 0.0, "npu_sim_exponential_ expects lambd > 0.0, but found lambd=", | 25 | + lambd > 0.0, "npu_sim_exponential_ expects lambd > 0.0, but found lambd=", lambd, OPS_ERROR(ErrCode::PARAM)); |
| 26 | - lambd, OPS_ERROR(ErrCode::PARAM)); | 26 | + if (std::isinf(lambd)) { |
| 27 | - if (std::isinf(lambd)) { | 27 | + self.zero_(); |
| 28 | - self.zero_(); | ||
| 29 | - return self; | ||
| 30 | - } | ||
| 31 | - | ||
| 32 | - auto gen = at::get_generator_or_default<at_npu::NPUGeneratorImpl>(generator, at_npu::detail::getDefaultNPUGenerator()); | ||
| 33 | - // Remove false after aclnnSimThreadExponential supports aclnnSetPytorchRandom. | ||
| 34 | - auto counter_offset = op_plugin::utils::calc_final_counter_offset(self, false); | ||
| 35 | - auto pair = gen->philox_engine_inputs(counter_offset); | ||
| 36 | - int64_t seed = static_cast<int64_t>(pair.first); | ||
| 37 | - int64_t offset = static_cast<int64_t>(pair.second); | ||
| 38 | - int64_t count = self.numel(); | ||
| 39 | - ASCEND_LOGI("count:%lld, lambd:%lf, seed:%lld, offset:%lld", count, lambd, seed, offset); | ||
| 40 | - | ||
| 41 | - EXEC_NPU_CMD(aclnnSimThreadExponential, self, count, lambd, seed, offset); | ||
| 42 | return self; | 28 | return self; |
| 29 | + } | ||
| 30 | + | ||
| 31 | + auto gen = | ||
| 32 | + at::get_generator_or_default<at_npu::NPUGeneratorImpl>(generator, at_npu::detail::getDefaultNPUGenerator()); | ||
| 33 | + // Remove false after aclnnSimThreadExponential supports aclnnSetPytorchRandom. | ||
| 34 | + auto counter_offset = op_plugin::utils::calc_final_counter_offset(self, false); | ||
| 35 | + auto pair = gen->philox_engine_inputs(counter_offset); | ||
| 36 | + int64_t seed = static_cast<int64_t>(pair.first); | ||
| 37 | + int64_t offset = static_cast<int64_t>(pair.second); | ||
| 38 | + int64_t count = self.numel(); | ||
| 39 | + ASCEND_LOGI("count:%lld, lambd:%lf, seed:%lld, offset:%lld", count, lambd, seed, offset); | ||
| 40 | + | ||
| 41 | + EXEC_NPU_CMD(aclnnSimThreadExponential, self, count, lambd, seed, offset); | ||
| 42 | + return self; | ||
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | -} // namespace op_api | 45 | +} // namespace op_api |
| @@ -20,21 +20,23 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -std::tuple<at::Tensor, at::Tensor> slogdet(const at::Tensor& self) | 23 | +std::tuple<at::Tensor, at::Tensor> slogdet(const at::Tensor& self) { |
| 24 | -{ | 24 | + DO_COMPATIBILITY(aclnnSlogdet, acl_op::slogdet(self)); |
| 25 | - DO_COMPATIBILITY(aclnnSlogdet, acl_op::slogdet(self)); | 25 | + // input dimension at least 2 |
| 26 | - // input dimension at least 2 | 26 | + TORCH_CHECK( |
| 27 | - TORCH_CHECK(self.ndimension() >= 2, "Expected nonempty least 2D tensor, but got a tensor with sizes ", self.dim(), | 27 | + self.ndimension() >= 2, |
| 28 | - OPS_ERROR(ErrCode::PARAM)); | 28 | + "Expected nonempty least 2D tensor, but got a tensor with sizes ", |
| 29 | - // calculate the output size | 29 | + self.dim(), |
| 30 | - auto outputSize = op_infer::array_to_small_vector(self.sizes()); | 30 | + OPS_ERROR(ErrCode::PARAM)); |
| 31 | - outputSize.erase(outputSize.end() - 2, outputSize.end()); | 31 | + // calculate the output size |
| 32 | - // construct the output tensor of the NPU | 32 | + auto outputSize = op_infer::array_to_small_vector(self.sizes()); |
| 33 | - at::Tensor sign = npu_preparation::apply_tensor(self, outputSize); | 33 | + outputSize.erase(outputSize.end() - 2, outputSize.end()); |
| 34 | - at::Tensor log = npu_preparation::apply_tensor(self, outputSize); | 34 | + // construct the output tensor of the NPU |
| 35 | - // calculate the output result of the NPU | 35 | + at::Tensor sign = npu_preparation::apply_tensor(self, outputSize); |
| 36 | - EXEC_NPU_CMD(aclnnSlogdet, self, sign, log); | 36 | + at::Tensor log = npu_preparation::apply_tensor(self, outputSize); |
| 37 | + // calculate the output result of the NPU | ||
| 38 | + EXEC_NPU_CMD(aclnnSlogdet, self, sign, log); | ||
| 37 | 39 | ||
| 38 | - return std::tie(sign, log); | 40 | + return std::tie(sign, log); |
| 39 | -} | ||
| 40 | } | 41 | } |
| 42 | +} // namespace op_api | ||
| @@ -26,10 +26,10 @@ at::Tensor& smooth_l1_loss_backward_out( | |||
| 26 | const at::Tensor& target, | 26 | const at::Tensor& target, |
| 27 | int64_t reduction, | 27 | int64_t reduction, |
| 28 | double beta, | 28 | double beta, |
| 29 | - at::Tensor& grad_input) | 29 | + at::Tensor& grad_input) { |
| 30 | -{ | 30 | + DO_COMPATIBILITY( |
| 31 | - DO_COMPATIBILITY(aclnnSmoothL1LossBackward, | 31 | + aclnnSmoothL1LossBackward, |
| 32 | - acl_op::smooth_l1_loss_backward_out(grad_out, self, target, reduction, beta, grad_input)); | 32 | + acl_op::smooth_l1_loss_backward_out(grad_out, self, target, reduction, beta, grad_input)); |
| 33 | auto mid_shape = op_infer::broadcast_ops_npu_output_size(self.sizes(), target.sizes()); | 33 | auto mid_shape = op_infer::broadcast_ops_npu_output_size(self.sizes(), target.sizes()); |
| 34 | auto output_size = op_infer::broadcast_ops_npu_output_size(mid_shape, grad_out.sizes()); | 34 | auto output_size = op_infer::broadcast_ops_npu_output_size(mid_shape, grad_out.sizes()); |
| 35 | npu_preparation::check_tensor({grad_out, self, target}, grad_input, grad_input.scalar_type(), output_size); | 35 | npu_preparation::check_tensor({grad_out, self, target}, grad_input, grad_input.scalar_type(), output_size); |
| @@ -43,10 +43,8 @@ at::Tensor smooth_l1_loss_backward( | |||
| 43 | const at::Tensor& self, | 43 | const at::Tensor& self, |
| 44 | const at::Tensor& target, | 44 | const at::Tensor& target, |
| 45 | int64_t reduction, | 45 | int64_t reduction, |
| 46 | - double beta) | 46 | + double beta) { |
| 47 | -{ | 47 | + DO_COMPATIBILITY(aclnnSmoothL1LossBackward, acl_op::smooth_l1_loss_backward(grad_out, self, target, reduction, beta)); |
| 48 | - DO_COMPATIBILITY(aclnnSmoothL1LossBackward, | ||
| 49 | - acl_op::smooth_l1_loss_backward(grad_out, self, target, reduction, beta)); | ||
| 50 | auto mid_shape = op_infer::broadcast_ops_npu_output_size(self.sizes(), target.sizes()); | 48 | auto mid_shape = op_infer::broadcast_ops_npu_output_size(self.sizes(), target.sizes()); |
| 51 | auto output_size = op_infer::broadcast_ops_npu_output_size(mid_shape, grad_out.sizes()); | 49 | auto output_size = op_infer::broadcast_ops_npu_output_size(mid_shape, grad_out.sizes()); |
| 52 | at::Tensor grad_input = npu_preparation::apply_tensor_without_format(self, output_size); | 50 | at::Tensor grad_input = npu_preparation::apply_tensor_without_format(self, output_size); |
| @@ -55,4 +53,4 @@ at::Tensor smooth_l1_loss_backward( | |||
| 55 | return grad_input; | 53 | return grad_input; |
| 56 | } | 54 | } |
| 57 | 55 | ||
| 58 | -} | 56 | +} // namespace op_api |
| @@ -20,26 +20,28 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -at::Tensor &smooth_l1_loss_out(const at::Tensor &self, const at::Tensor &target, int64_t reduction, double beta, | 23 | +at::Tensor& smooth_l1_loss_out( |
| 24 | - at::Tensor &out) | 24 | + const at::Tensor& self, |
| 25 | -{ | 25 | + const at::Tensor& target, |
| 26 | - DO_COMPATIBILITY(aclnnSmoothL1Loss, acl_op::smooth_l1_loss_out(self, target, reduction, beta, out)); | 26 | + int64_t reduction, |
| 27 | - auto outputSize = op_infer::smooth_l1_loss_npu_output_size(self, reduction); | 27 | + double beta, |
| 28 | - npu_preparation::check_tensor({self, target}, out, out.scalar_type(), outputSize); | 28 | + at::Tensor& out) { |
| 29 | - npu_preparation::check_memory({self, target}, {out}); | 29 | + DO_COMPATIBILITY(aclnnSmoothL1Loss, acl_op::smooth_l1_loss_out(self, target, reduction, beta, out)); |
| 30 | - float sigma = static_cast<float>(beta); | 30 | + auto outputSize = op_infer::smooth_l1_loss_npu_output_size(self, reduction); |
| 31 | - EXEC_NPU_CMD(aclnnSmoothL1Loss, self, target, reduction, sigma, out); | 31 | + npu_preparation::check_tensor({self, target}, out, out.scalar_type(), outputSize); |
| 32 | - return out; | 32 | + npu_preparation::check_memory({self, target}, {out}); |
| 33 | + float sigma = static_cast<float>(beta); | ||
| 34 | + EXEC_NPU_CMD(aclnnSmoothL1Loss, self, target, reduction, sigma, out); | ||
| 35 | + return out; | ||
| 33 | } | 36 | } |
| 34 | 37 | ||
| 35 | -at::Tensor smooth_l1_loss(const at::Tensor &self, const at::Tensor &target, int64_t reduction, double beta) | 38 | +at::Tensor smooth_l1_loss(const at::Tensor& self, const at::Tensor& target, int64_t reduction, double beta) { |
| 36 | -{ | 39 | + DO_COMPATIBILITY(aclnnSmoothL1Loss, acl_op::smooth_l1_loss(self, target, reduction, beta)); |
| 37 | - DO_COMPATIBILITY(aclnnSmoothL1Loss, acl_op::smooth_l1_loss(self, target, reduction, beta)); | 40 | + auto outputSize = op_infer::smooth_l1_loss_npu_output_size(self, reduction); |
| 38 | - auto outputSize = op_infer::smooth_l1_loss_npu_output_size(self, reduction); | 41 | + at::ScalarType high_type = at::native::result_type(self, target); |
| 39 | - at::ScalarType high_type = at::native::result_type(self, target); | 42 | + at::Tensor result = npu_preparation::apply_tensor_without_format(outputSize, self.options().dtype(high_type)); |
| 40 | - at::Tensor result = npu_preparation::apply_tensor_without_format(outputSize, self.options().dtype(high_type)); | 43 | + float sigma = static_cast<float>(beta); |
| 41 | - float sigma = static_cast<float>(beta); | 44 | + EXEC_NPU_CMD(aclnnSmoothL1Loss, self, target, reduction, sigma, result); |
| 42 | - EXEC_NPU_CMD(aclnnSmoothL1Loss, self, target, reduction, sigma, result); | 45 | + return result; |
| 43 | - return result; | ||
| 44 | -} | ||
| 45 | } | 46 | } |
| 47 | +} // namespace op_api | ||
| @@ -20,90 +20,96 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -std::tuple<at::Tensor &, at::Tensor &> sort_output(const at::Tensor &self, bool stable, int64_t dim, bool descending, | 23 | +std::tuple<at::Tensor&, at::Tensor&> sort_output( |
| 24 | - at::Tensor &values, at::Tensor &indices) | 24 | + const at::Tensor& self, |
| 25 | -{ | 25 | + bool stable, |
| 26 | - EXEC_NPU_CMD(aclnnSort, self, stable, dim, descending, values, indices); | 26 | + int64_t dim, |
| 27 | - return std::tie(values, indices); | 27 | + bool descending, |
| 28 | + at::Tensor& values, | ||
| 29 | + at::Tensor& indices) { | ||
| 30 | + EXEC_NPU_CMD(aclnnSort, self, stable, dim, descending, values, indices); | ||
| 31 | + return std::tie(values, indices); | ||
| 28 | } | 32 | } |
| 29 | 33 | ||
| 30 | -std::tuple<at::Tensor, at::Tensor> sort(const at::Tensor &self, int64_t dim, bool descending) | 34 | +std::tuple<at::Tensor, at::Tensor> sort(const at::Tensor& self, int64_t dim, bool descending) { |
| 31 | -{ | 35 | + DO_COMPATIBILITY(aclnnSort, acl_op::sort(self, dim, descending)); |
| 32 | - DO_COMPATIBILITY(aclnnSort, acl_op::sort(self, dim, descending)); | 36 | + at::Tensor values = npu_preparation::apply_tensor_without_format(self); |
| 33 | - at::Tensor values = npu_preparation::apply_tensor_without_format(self); | 37 | + at::Tensor indices = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(at::kLong)); |
| 34 | - at::Tensor indices = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(at::kLong)); | 38 | + bool stable = false; |
| 35 | - bool stable = false; | ||
| 36 | 39 | ||
| 37 | - return sort_output(self, stable, dim, descending, values, indices); | 40 | + return sort_output(self, stable, dim, descending, values, indices); |
| 38 | } | 41 | } |
| 39 | 42 | ||
| 40 | 43 | ||
| 41 | -std::tuple<at::Tensor, at::Tensor> sort(const at::Tensor &self, at::Dimname dim, bool descending) | 44 | +std::tuple<at::Tensor, at::Tensor> sort(const at::Tensor& self, at::Dimname dim, bool descending) { |
| 42 | -{ | 45 | + DO_COMPATIBILITY(aclnnSort, acl_op::sort(self, dim, descending)); |
| 43 | - DO_COMPATIBILITY(aclnnSort, acl_op::sort(self, dim, descending)); | 46 | + at::Tensor values = npu_preparation::apply_tensor_without_format(self); |
| 44 | - at::Tensor values = npu_preparation::apply_tensor_without_format(self); | 47 | + at::Tensor indices = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(at::kLong)); |
| 45 | - at::Tensor indices = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(at::kLong)); | 48 | + bool stable = false; |
| 46 | - bool stable = false; | 49 | + int64_t argDim = dimname_to_position(self, dim); |
| 47 | - int64_t argDim = dimname_to_position(self, dim); | ||
| 48 | 50 | ||
| 49 | - return sort_output(self, stable, argDim, descending, values, indices); | 51 | + return sort_output(self, stable, argDim, descending, values, indices); |
| 50 | } | 52 | } |
| 51 | 53 | ||
| 52 | 54 | ||
| 53 | -std::tuple<at::Tensor &, at::Tensor &> sort_out(const at::Tensor &self, int64_t dim, | 55 | +std::tuple<at::Tensor&, at::Tensor&> sort_out( |
| 54 | - bool descending, at::Tensor &values, at::Tensor &indices) | 56 | + const at::Tensor& self, |
| 55 | -{ | 57 | + int64_t dim, |
| 56 | - DO_COMPATIBILITY(aclnnSort, acl_op::sort_out(self, dim, descending, values, indices)); | 58 | + bool descending, |
| 57 | - npu_preparation::check_tensor({self}, values, values.scalar_type(), self.sizes()); | 59 | + at::Tensor& values, |
| 58 | - npu_preparation::check_tensor({self}, indices, indices.scalar_type(), self.sizes()); | 60 | + at::Tensor& indices) { |
| 59 | - bool stable = false; | 61 | + DO_COMPATIBILITY(aclnnSort, acl_op::sort_out(self, dim, descending, values, indices)); |
| 62 | + npu_preparation::check_tensor({self}, values, values.scalar_type(), self.sizes()); | ||
| 63 | + npu_preparation::check_tensor({self}, indices, indices.scalar_type(), self.sizes()); | ||
| 64 | + bool stable = false; | ||
| 60 | 65 | ||
| 61 | - return sort_output(self, stable, dim, descending, values, indices); | 66 | + return sort_output(self, stable, dim, descending, values, indices); |
| 62 | } | 67 | } |
| 63 | 68 | ||
| 64 | 69 | ||
| 65 | -std::tuple<at::Tensor &, at::Tensor &> sort_out(const at::Tensor &self, at::Dimname dim, | 70 | +std::tuple<at::Tensor&, at::Tensor&> sort_out( |
| 66 | - bool descending, at::Tensor &values, at::Tensor &indices) | 71 | + const at::Tensor& self, |
| 67 | -{ | 72 | + at::Dimname dim, |
| 68 | - DO_COMPATIBILITY(aclnnSort, acl_op::sort_out(self, dim, descending, values, indices)); | 73 | + bool descending, |
| 69 | - npu_preparation::check_tensor({self}, values, values.scalar_type(), self.sizes()); | 74 | + at::Tensor& values, |
| 70 | - npu_preparation::check_tensor({self}, indices, indices.scalar_type(), self.sizes()); | 75 | + at::Tensor& indices) { |
| 71 | - bool stable = false; | 76 | + DO_COMPATIBILITY(aclnnSort, acl_op::sort_out(self, dim, descending, values, indices)); |
| 77 | + npu_preparation::check_tensor({self}, values, values.scalar_type(), self.sizes()); | ||
| 78 | + npu_preparation::check_tensor({self}, indices, indices.scalar_type(), self.sizes()); | ||
| 79 | + bool stable = false; | ||
| 72 | 80 | ||
| 73 | - return sort_output(self, stable, dimname_to_position(self, dim), descending, values, indices); | 81 | + return sort_output(self, stable, dimname_to_position(self, dim), descending, values, indices); |
| 74 | } | 82 | } |
| 75 | 83 | ||
| 76 | 84 | ||
| 77 | -std::tuple<at::Tensor, at::Tensor> sort(const at::Tensor &self, | 85 | +std::tuple<at::Tensor, at::Tensor> sort( |
| 78 | - c10::optional<bool> stable, | 86 | + const at::Tensor& self, |
| 79 | - int64_t dim, | 87 | + c10::optional<bool> stable, |
| 80 | - bool descending) | 88 | + int64_t dim, |
| 81 | -{ | 89 | + bool descending) { |
| 82 | - auto dtype = self.scalar_type(); | 90 | + auto dtype = self.scalar_type(); |
| 83 | - TORCH_CHECK(!(dtype == at::kDouble), | 91 | + TORCH_CHECK(!(dtype == at::kDouble), "Input data type should not be float64 " + OPS_ERROR(ErrCode::TYPE)); |
| 84 | - "Input data type should not be float64 " + OPS_ERROR(ErrCode::TYPE)); | 92 | + at::Tensor values = npu_preparation::apply_tensor_without_format(self); |
| 85 | - at::Tensor values = npu_preparation::apply_tensor_without_format(self); | 93 | + at::Tensor indices = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(at::kLong)); |
| 86 | - at::Tensor indices = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(at::kLong)); | 94 | + bool argStable = c10::value_or_else(stable, [] { return false; }); |
| 87 | - bool argStable = c10::value_or_else(stable, [] { return false; }); | 95 | + EXEC_NPU_CMD(aclnnSort, self, argStable, dim, descending, values, indices); |
| 88 | - EXEC_NPU_CMD(aclnnSort, self, argStable, dim, descending, values, indices); | 96 | + return std::tie(values, indices); |
| 89 | - return std::tie(values, indices); | ||
| 90 | } | 97 | } |
| 91 | 98 | ||
| 92 | -std::tuple<at::Tensor &, at::Tensor &> sort_out(const at::Tensor &self, | 99 | +std::tuple<at::Tensor&, at::Tensor&> sort_out( |
| 93 | - c10::optional<bool> stable, | 100 | + const at::Tensor& self, |
| 94 | - int64_t dim, | 101 | + c10::optional<bool> stable, |
| 95 | - bool descending, | 102 | + int64_t dim, |
| 96 | - at::Tensor &values, | 103 | + bool descending, |
| 97 | - at::Tensor &indices) | 104 | + at::Tensor& values, |
| 98 | -{ | 105 | + at::Tensor& indices) { |
| 99 | - auto dtype = self.scalar_type(); | 106 | + auto dtype = self.scalar_type(); |
| 100 | - TORCH_CHECK(!(dtype == at::kDouble), | 107 | + TORCH_CHECK(!(dtype == at::kDouble), "Input data type should not be float64 " + OPS_ERROR(ErrCode::TYPE)); |
| 101 | - "Input data type should not be float64 " + OPS_ERROR(ErrCode::TYPE)); | 108 | + npu_preparation::check_tensor({self}, values, values.scalar_type(), self.sizes()); |
| 102 | - npu_preparation::check_tensor({self}, values, values.scalar_type(), self.sizes()); | 109 | + npu_preparation::check_tensor({self}, indices, indices.scalar_type(), self.sizes()); |
| 103 | - npu_preparation::check_tensor({self}, indices, indices.scalar_type(), self.sizes()); | 110 | + bool argStable = c10::value_or_else(stable, [] { return false; }); |
| 104 | - bool argStable = c10::value_or_else(stable, [] { return false; }); | 111 | + EXEC_NPU_CMD(aclnnSort, self, argStable, dim, descending, values, indices); |
| 105 | - EXEC_NPU_CMD(aclnnSort, self, argStable, dim, descending, values, indices); | 112 | + return std::tie(values, indices); |
| 106 | - return std::tie(values, indices); | ||
| 107 | } | 113 | } |
| 108 | 114 | ||
| 109 | -} // namespace op_api | 115 | +} // namespace op_api |
| @@ -26,79 +26,114 @@ const int DIMENSION_3D = 3; | |||
| 26 | const int DIMENSION_4D = 4; | 26 | const int DIMENSION_4D = 4; |
| 27 | 27 | ||
| 28 | std::tuple<at::Tensor, at::Tensor, at::Tensor, at::Tensor, at::Tensor> npu_sparse_flash_attention_grad( | 28 | std::tuple<at::Tensor, at::Tensor, at::Tensor, at::Tensor, at::Tensor> npu_sparse_flash_attention_grad( |
| 29 | - const at::Tensor &query, | 29 | + const at::Tensor& query, |
| 30 | - const at::Tensor &key, | 30 | + const at::Tensor& key, |
| 31 | - const at::Tensor &value, | 31 | + const at::Tensor& value, |
| 32 | - const at::Tensor &sparse_indices, | 32 | + const at::Tensor& sparse_indices, |
| 33 | - const at::Tensor &d_out, | 33 | + const at::Tensor& d_out, |
| 34 | - const at::Tensor &out, | 34 | + const at::Tensor& out, |
| 35 | - const at::Tensor &softmax_max, | 35 | + const at::Tensor& softmax_max, |
| 36 | - const at::Tensor &softmax_sum, | 36 | + const at::Tensor& softmax_sum, |
| 37 | double scale_value, | 37 | double scale_value, |
| 38 | int64_t sparse_block_size, | 38 | int64_t sparse_block_size, |
| 39 | - const c10::optional<at::Tensor> &query_rope, | 39 | + const c10::optional<at::Tensor>& query_rope, |
| 40 | - const c10::optional<at::Tensor> &key_rope, | 40 | + const c10::optional<at::Tensor>& key_rope, |
| 41 | - const c10::optional<at::Tensor> &actual_seq_qlen, | 41 | + const c10::optional<at::Tensor>& actual_seq_qlen, |
| 42 | - const c10::optional<at::Tensor> &actual_seq_kvlen, | 42 | + const c10::optional<at::Tensor>& actual_seq_kvlen, |
| 43 | c10::optional<c10::string_view> layout, | 43 | c10::optional<c10::string_view> layout, |
| 44 | c10::optional<int64_t> sparse_mode, | 44 | c10::optional<int64_t> sparse_mode, |
| 45 | c10::optional<int64_t> pre_tokens, | 45 | c10::optional<int64_t> pre_tokens, |
| 46 | c10::optional<int64_t> next_tokens, | 46 | c10::optional<int64_t> next_tokens, |
| 47 | - c10::optional<int64_t> attention_mode) | 47 | + c10::optional<int64_t> attention_mode) { |
| 48 | -{ | 48 | + const at::Tensor& query_rope_const = query_rope.value_or(at::Tensor()); |
| 49 | - const at::Tensor &query_rope_const = query_rope.value_or(at::Tensor()); | 49 | + const at::Tensor& key_rope_const = key_rope.value_or(at::Tensor()); |
| 50 | - const at::Tensor &key_rope_const = key_rope.value_or(at::Tensor()); | 50 | + const at::Tensor& ac_seq_qlen = actual_seq_qlen.value_or(at::Tensor()); |
| 51 | - const at::Tensor &ac_seq_qlen = actual_seq_qlen.value_or(at::Tensor()); | 51 | + const at::Tensor& ac_seq_kvlen = actual_seq_kvlen.value_or(at::Tensor()); |
| 52 | - const at::Tensor &ac_seq_kvlen = actual_seq_kvlen.value_or(at::Tensor()); | 52 | + TORCH_CHECK( |
| 53 | - TORCH_CHECK(query.dim() == DIMENSION_3D || query.dim() == DIMENSION_4D, | 53 | + query.dim() == DIMENSION_3D || query.dim() == DIMENSION_4D, |
| 54 | - "The shapes of the input query should be 3 or 4 dimensional, but got ", | 54 | + "The shapes of the input query should be 3 or 4 dimensional, but got ", |
| 55 | - query.dim(), "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 55 | + query.dim(), |
| 56 | - if (query_rope_const.defined()) { | 56 | + "-dimensional", |
| 57 | - TORCH_CHECK(query_rope_const.dim() == DIMENSION_3D || query_rope_const.dim() == DIMENSION_4D, | 57 | + OPS_ERROR(ErrCode::PARAM)); |
| 58 | - "The shapes of the input query_rope should be 3 or 4 dimensional, but got ", | 58 | + if (query_rope_const.defined()) { |
| 59 | - query_rope_const.dim(), "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 59 | + TORCH_CHECK( |
| 60 | - } | 60 | + query_rope_const.dim() == DIMENSION_3D || query_rope_const.dim() == DIMENSION_4D, |
| 61 | - TORCH_CHECK(key.dim() == DIMENSION_3D || key.dim() == DIMENSION_4D, | 61 | + "The shapes of the input query_rope should be 3 or 4 dimensional, but got ", |
| 62 | - "The shapes of the input key should be 3 or 4 dimensional, but got ", key.dim(), | 62 | + query_rope_const.dim(), |
| 63 | - "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 63 | + "-dimensional", |
| 64 | - if (key_rope_const.defined()) { | 64 | + OPS_ERROR(ErrCode::PARAM)); |
| 65 | - TORCH_CHECK(key_rope_const.dim() == DIMENSION_3D || key_rope_const.dim() == DIMENSION_4D, | 65 | + } |
| 66 | - "The shapes of the input key_rope should be 3 or 4 dimensional, but got ", | 66 | + TORCH_CHECK( |
| 67 | - key_rope_const.dim(), "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 67 | + key.dim() == DIMENSION_3D || key.dim() == DIMENSION_4D, |
| 68 | - } | 68 | + "The shapes of the input key should be 3 or 4 dimensional, but got ", |
| 69 | - TORCH_CHECK(value.dim() == DIMENSION_3D || value.dim() == DIMENSION_4D, | 69 | + key.dim(), |
| 70 | - "The shapes of the input value should be 3 or 4 dimensional, but got ", | 70 | + "-dimensional", |
| 71 | - value.dim(), "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 71 | + OPS_ERROR(ErrCode::PARAM)); |
| 72 | - at::Tensor d_query = OpPreparation::apply_tensor_without_format(query); | 72 | + if (key_rope_const.defined()) { |
| 73 | - at::Tensor d_key = OpPreparation::apply_tensor_without_format(key); | 73 | + TORCH_CHECK( |
| 74 | - at::Tensor d_value = OpPreparation::apply_tensor_without_format(value); | 74 | + key_rope_const.dim() == DIMENSION_3D || key_rope_const.dim() == DIMENSION_4D, |
| 75 | - at::Tensor d_query_rope; | 75 | + "The shapes of the input key_rope should be 3 or 4 dimensional, but got ", |
| 76 | - at::Tensor d_key_rope; | 76 | + key_rope_const.dim(), |
| 77 | - if (query_rope_const.defined()) { | 77 | + "-dimensional", |
| 78 | - d_query_rope = OpPreparation::apply_tensor_without_format(query_rope_const); | 78 | + OPS_ERROR(ErrCode::PARAM)); |
| 79 | - } else { | 79 | + } |
| 80 | - d_query_rope = at::empty({0}, query.options()); | 80 | + TORCH_CHECK( |
| 81 | - } | 81 | + value.dim() == DIMENSION_3D || value.dim() == DIMENSION_4D, |
| 82 | - if (key_rope_const.defined()) { | 82 | + "The shapes of the input value should be 3 or 4 dimensional, but got ", |
| 83 | - d_key_rope = OpPreparation::apply_tensor_without_format(key_rope_const); | 83 | + value.dim(), |
| 84 | - } else { | 84 | + "-dimensional", |
| 85 | - d_key_rope = at::empty({0}, key.options()); | 85 | + OPS_ERROR(ErrCode::PARAM)); |
| 86 | - } | 86 | + at::Tensor d_query = OpPreparation::apply_tensor_without_format(query); |
| 87 | + at::Tensor d_key = OpPreparation::apply_tensor_without_format(key); | ||
| 88 | + at::Tensor d_value = OpPreparation::apply_tensor_without_format(value); | ||
| 89 | + at::Tensor d_query_rope; | ||
| 90 | + at::Tensor d_key_rope; | ||
| 91 | + if (query_rope_const.defined()) { | ||
| 92 | + d_query_rope = OpPreparation::apply_tensor_without_format(query_rope_const); | ||
| 93 | + } else { | ||
| 94 | + d_query_rope = at::empty({0}, query.options()); | ||
| 95 | + } | ||
| 96 | + if (key_rope_const.defined()) { | ||
| 97 | + d_key_rope = OpPreparation::apply_tensor_without_format(key_rope_const); | ||
| 98 | + } else { | ||
| 99 | + d_key_rope = at::empty({0}, key.options()); | ||
| 100 | + } | ||
| 87 | 101 | ||
| 88 | - c10::string_view layout_str_view = layout.value_or("BSND"); | 102 | + c10::string_view layout_str_view = layout.value_or("BSND"); |
| 89 | - char *layout_ptr = const_cast<char *>(layout_str_view.data()); | 103 | + char* layout_ptr = const_cast<char*>(layout_str_view.data()); |
| 90 | 104 | ||
| 91 | - const int64_t sparse_mode_const = sparse_mode.value_or(3); | 105 | + const int64_t sparse_mode_const = sparse_mode.value_or(3); |
| 92 | - const int64_t pre_tokens_const = pre_tokens.value_or(9223372036854775807); | 106 | + const int64_t pre_tokens_const = pre_tokens.value_or(9223372036854775807); |
| 93 | - const int64_t next_tokens_const = next_tokens.value_or(9223372036854775807); | 107 | + const int64_t next_tokens_const = next_tokens.value_or(9223372036854775807); |
| 94 | - const bool deterministic_const = true; | 108 | + const bool deterministic_const = true; |
| 95 | 109 | ||
| 96 | - EXEC_NPU_NO_FORMAT_CHECK_CMD( | 110 | + EXEC_NPU_NO_FORMAT_CHECK_CMD( |
| 97 | - aclnnSparseFlashAttentionGrad, query, key, value, sparse_indices, d_out, | 111 | + aclnnSparseFlashAttentionGrad, |
| 98 | - out, softmax_max, softmax_sum, ac_seq_qlen, ac_seq_kvlen, query_rope_const, key_rope_const, | 112 | + query, |
| 99 | - scale_value, sparse_block_size, layout_ptr, sparse_mode_const, pre_tokens_const, next_tokens_const, | 113 | + key, |
| 100 | - deterministic_const, d_query, d_key, d_value, d_query_rope, d_key_rope); | 114 | + value, |
| 115 | + sparse_indices, | ||
| 116 | + d_out, | ||
| 117 | + out, | ||
| 118 | + softmax_max, | ||
| 119 | + softmax_sum, | ||
| 120 | + ac_seq_qlen, | ||
| 121 | + ac_seq_kvlen, | ||
| 122 | + query_rope_const, | ||
| 123 | + key_rope_const, | ||
| 124 | + scale_value, | ||
| 125 | + sparse_block_size, | ||
| 126 | + layout_ptr, | ||
| 127 | + sparse_mode_const, | ||
| 128 | + pre_tokens_const, | ||
| 129 | + next_tokens_const, | ||
| 130 | + deterministic_const, | ||
| 131 | + d_query, | ||
| 132 | + d_key, | ||
| 133 | + d_value, | ||
| 134 | + d_query_rope, | ||
| 135 | + d_key_rope); | ||
| 101 | 136 | ||
| 102 | - return std::make_tuple(d_query, d_key, d_value, d_query_rope, d_key_rope); | 137 | + return std::make_tuple(d_query, d_key, d_value, d_query_rope, d_key_rope); |
| 103 | -} | ||
| 104 | } | 138 | } |
| 139 | +} // namespace op_api | ||
| @@ -29,94 +29,147 @@ const static int64_t DIM_4 = 4; | |||
| 29 | using npu_preparation = at_npu::native::OpPreparation; | 29 | using npu_preparation = at_npu::native::OpPreparation; |
| 30 | 30 | ||
| 31 | namespace { | 31 | namespace { |
| 32 | -at::Tensor construct_sparse_flash_attention_output_tensor( | 32 | +at::Tensor construct_sparse_flash_attention_output_tensor(const at::Tensor& query, std::string layout) { |
| 33 | - const at::Tensor& query, std::string layout) | 33 | + TORCH_CHECK( |
| 34 | -{ | 34 | + layout == "BSND" || layout == "TND", |
| 35 | - TORCH_CHECK(layout == "BSND" || layout == "TND", "The layout of query only support BSND and TND, but got ", | 35 | + "The layout of query only support BSND and TND, but got ", |
| 36 | - layout, OPS_ERROR(ErrCode::PARAM)); | 36 | + layout, |
| 37 | - at::SmallVector<int64_t, SIZE> output_size; | 37 | + OPS_ERROR(ErrCode::PARAM)); |
| 38 | - for (size_t i = 0; i < query.sizes().size(); i++) { | 38 | + at::SmallVector<int64_t, SIZE> output_size; |
| 39 | - TORCH_CHECK(query.size(i) > 0, "All values within query's shape should be greater " | 39 | + for (size_t i = 0; i < query.sizes().size(); i++) { |
| 40 | - "than 0, but shape[", i, "] is ", query.size(i), OPS_ERROR(ErrCode::PARAM)); | 40 | + TORCH_CHECK( |
| 41 | - } | 41 | + query.size(i) > 0, |
| 42 | - if (layout == "TND") { | 42 | + "All values within query's shape should be greater " |
| 43 | - TORCH_CHECK(query.dim() == DIM_3, | 43 | + "than 0, but shape[", |
| 44 | - "When the layout of query is TND, the query dimension must be 3, but got ", | 44 | + i, |
| 45 | - query.dim(), OPS_ERROR(ErrCode::PARAM)); | 45 | + "] is ", |
| 46 | - output_size = {query.size(DIM_0), query.size(DIM_1), query.size(DIM_2)}; | 46 | + query.size(i), |
| 47 | - } else { | 47 | + OPS_ERROR(ErrCode::PARAM)); |
| 48 | - TORCH_CHECK(query.dim() == DIM_4, | 48 | + } |
| 49 | - "When the layout of query is BSND, the query dimension must be 4, but got ", | 49 | + if (layout == "TND") { |
| 50 | - query.dim(), OPS_ERROR(ErrCode::PARAM)); | 50 | + TORCH_CHECK( |
| 51 | - output_size = {query.size(DIM_0), query.size(DIM_1), query.size(DIM_2), query.size(DIM_3)}; | 51 | + query.dim() == DIM_3, |
| 52 | - } | 52 | + "When the layout of query is TND, the query dimension must be 3, but got ", |
| 53 | - at::Tensor output = npu_preparation::apply_tensor_without_format(output_size, query.options().dtype(query.dtype())); | 53 | + query.dim(), |
| 54 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 55 | + output_size = {query.size(DIM_0), query.size(DIM_1), query.size(DIM_2)}; | ||
| 56 | + } else { | ||
| 57 | + TORCH_CHECK( | ||
| 58 | + query.dim() == DIM_4, | ||
| 59 | + "When the layout of query is BSND, the query dimension must be 4, but got ", | ||
| 60 | + query.dim(), | ||
| 61 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 62 | + output_size = {query.size(DIM_0), query.size(DIM_1), query.size(DIM_2), query.size(DIM_3)}; | ||
| 63 | + } | ||
| 64 | + at::Tensor output = npu_preparation::apply_tensor_without_format(output_size, query.options().dtype(query.dtype())); | ||
| 54 | 65 | ||
| 55 | - return output; | 66 | + return output; |
| 56 | } | 67 | } |
| 57 | -} | 68 | +} // namespace |
| 58 | - | ||
| 59 | 69 | ||
| 60 | std::tuple<at::Tensor, at::Tensor, at::Tensor> npu_sparse_flash_attention( | 70 | std::tuple<at::Tensor, at::Tensor, at::Tensor> npu_sparse_flash_attention( |
| 61 | - const at::Tensor &query, const at::Tensor &key, const at::Tensor &value, | 71 | + const at::Tensor& query, |
| 62 | - const at::Tensor &sparse_indices, double scale_value, | 72 | + const at::Tensor& key, |
| 63 | - const c10::optional<at::Tensor> &block_table, | 73 | + const at::Tensor& value, |
| 64 | - const c10::optional<at::Tensor> &actual_seq_lengths_query, | 74 | + const at::Tensor& sparse_indices, |
| 65 | - const c10::optional<at::Tensor> &actual_seq_lengths_kv, | 75 | + double scale_value, |
| 66 | - const c10::optional<at::Tensor> &query_rope, | 76 | + const c10::optional<at::Tensor>& block_table, |
| 67 | - const c10::optional<at::Tensor> &key_rope, int64_t sparse_block_size, | 77 | + const c10::optional<at::Tensor>& actual_seq_lengths_query, |
| 68 | - c10::string_view layout_query, c10::string_view layout_kv, | 78 | + const c10::optional<at::Tensor>& actual_seq_lengths_kv, |
| 69 | - int64_t sparse_mode, int64_t pre_tokens, int64_t next_tokens, | 79 | + const c10::optional<at::Tensor>& query_rope, |
| 70 | - int64_t attention_mode, bool return_softmax_lse, | 80 | + const c10::optional<at::Tensor>& key_rope, |
| 71 | - const c10::optional<at::Tensor> &sinks) | 81 | + int64_t sparse_block_size, |
| 72 | -{ | 82 | + c10::string_view layout_query, |
| 73 | - TORCH_CHECK(query.numel() > 0, "Tensor query is empty.", OPS_ERROR(ErrCode::PARAM)); | 83 | + c10::string_view layout_kv, |
| 74 | - TORCH_CHECK(key.numel() > 0, "Tensor key is empty.", OPS_ERROR(ErrCode::PARAM)); | 84 | + int64_t sparse_mode, |
| 75 | - TORCH_CHECK(sparse_indices.numel() > 0, "Tensor sparse_indices is empty.") | 85 | + int64_t pre_tokens, |
| 86 | + int64_t next_tokens, | ||
| 87 | + int64_t attention_mode, | ||
| 88 | + bool return_softmax_lse, | ||
| 89 | + const c10::optional<at::Tensor>& sinks) { | ||
| 90 | + TORCH_CHECK(query.numel() > 0, "Tensor query is empty.", OPS_ERROR(ErrCode::PARAM)); | ||
| 91 | + TORCH_CHECK(key.numel() > 0, "Tensor key is empty.", OPS_ERROR(ErrCode::PARAM)); | ||
| 92 | + TORCH_CHECK(sparse_indices.numel() > 0, "Tensor sparse_indices is empty.") | ||
| 76 | 93 | ||
| 77 | - std::string layout_query_str = std::string(layout_query); | 94 | + std::string layout_query_str = std::string(layout_query); |
| 78 | - std::string layout_kv_str = std::string(layout_kv); | 95 | + std::string layout_kv_str = std::string(layout_kv); |
| 79 | 96 | ||
| 80 | - // construct the output tensor | 97 | + // construct the output tensor |
| 81 | - at::Tensor sparse_flash_attention_output = construct_sparse_flash_attention_output_tensor( | 98 | + at::Tensor sparse_flash_attention_output = construct_sparse_flash_attention_output_tensor(query, layout_query_str); |
| 82 | - query, layout_query_str); | 99 | + at::Tensor softmax_max; |
| 83 | - at::Tensor softmax_max; | 100 | + at::Tensor softmax_sum; |
| 84 | - at::Tensor softmax_sum; | 101 | + at::SmallVector<int64_t, SIZE> softmax_max_size; |
| 85 | - at::SmallVector<int64_t, SIZE> softmax_max_size; | 102 | + at::SmallVector<int64_t, SIZE> softmax_sum_size; |
| 86 | - at::SmallVector<int64_t, SIZE> softmax_sum_size; | 103 | + if (return_softmax_lse) { |
| 87 | - if (return_softmax_lse) { | 104 | + if (query.dim() == DIM_3) { |
| 88 | - if (query.dim() == DIM_3) { | 105 | + softmax_max_size = {key.size(1), query.size(0), query.size(1) / key.size(1)}; |
| 89 | - softmax_max_size = {key.size(1), query.size(0), query.size(1) / key.size(1)}; | 106 | + softmax_sum_size = {key.size(1), query.size(0), query.size(1) / key.size(1)}; |
| 90 | - softmax_sum_size = {key.size(1), query.size(0), query.size(1) / key.size(1)}; | ||
| 91 | - } else { | ||
| 92 | - softmax_max_size = {query.size(0), key.size(2), query.size(1), query.size(2) / key.size(2)}; | ||
| 93 | - softmax_sum_size = {query.size(0), key.size(2), query.size(1), query.size(2) / key.size(2)}; | ||
| 94 | - } | ||
| 95 | } else { | 107 | } else { |
| 96 | - softmax_max_size = {0}; | 108 | + softmax_max_size = {query.size(0), key.size(2), query.size(1), query.size(2) / key.size(2)}; |
| 97 | - softmax_sum_size = {0}; | 109 | + softmax_sum_size = {query.size(0), key.size(2), query.size(1), query.size(2) / key.size(2)}; |
| 98 | } | 110 | } |
| 99 | - softmax_max = at::empty(softmax_max_size, query.options().dtype(at::kFloat)); | 111 | + } else { |
| 100 | - softmax_sum = at::empty(softmax_sum_size, query.options().dtype(at::kFloat)); | 112 | + softmax_max_size = {0}; |
| 101 | - // convert str | 113 | + softmax_sum_size = {0}; |
| 102 | - char *layout_query_ptr = const_cast<char *>(layout_query_str.c_str()); | 114 | + } |
| 103 | - char *layout_kv_ptr = const_cast<char *>(layout_kv_str.c_str()); | 115 | + softmax_max = at::empty(softmax_max_size, query.options().dtype(at::kFloat)); |
| 116 | + softmax_sum = at::empty(softmax_sum_size, query.options().dtype(at::kFloat)); | ||
| 117 | + // convert str | ||
| 118 | + char* layout_query_ptr = const_cast<char*>(layout_query_str.c_str()); | ||
| 119 | + char* layout_kv_ptr = const_cast<char*>(layout_kv_str.c_str()); | ||
| 104 | 120 | ||
| 105 | - if (sinks.has_value() && sinks->defined()) { | 121 | + if (sinks.has_value() && sinks->defined()) { |
| 106 | - EXEC_NPU_NO_FORMAT_CHECK_CMD(aclnnSparseFlashAttentionV2, query, | 122 | + EXEC_NPU_NO_FORMAT_CHECK_CMD( |
| 107 | - key, value, sparse_indices, block_table, actual_seq_lengths_query, | 123 | + aclnnSparseFlashAttentionV2, |
| 108 | - actual_seq_lengths_kv, query_rope, key_rope, sinks, scale_value, sparse_block_size, | 124 | + query, |
| 109 | - layout_query_ptr, layout_kv_ptr, sparse_mode, pre_tokens, next_tokens, attention_mode, return_softmax_lse, | 125 | + key, |
| 110 | - sparse_flash_attention_output, softmax_max, softmax_sum); | 126 | + value, |
| 111 | - } else { | 127 | + sparse_indices, |
| 112 | - EXEC_NPU_NO_FORMAT_CHECK_CMD(aclnnSparseFlashAttention, query, | 128 | + block_table, |
| 113 | - key, value, sparse_indices, block_table, actual_seq_lengths_query, | 129 | + actual_seq_lengths_query, |
| 114 | - actual_seq_lengths_kv, query_rope, key_rope, scale_value, sparse_block_size, | 130 | + actual_seq_lengths_kv, |
| 115 | - layout_query_ptr, layout_kv_ptr, sparse_mode, pre_tokens, next_tokens, attention_mode, return_softmax_lse, | 131 | + query_rope, |
| 116 | - sparse_flash_attention_output, softmax_max, softmax_sum); | 132 | + key_rope, |
| 117 | - } | 133 | + sinks, |
| 134 | + scale_value, | ||
| 135 | + sparse_block_size, | ||
| 136 | + layout_query_ptr, | ||
| 137 | + layout_kv_ptr, | ||
| 138 | + sparse_mode, | ||
| 139 | + pre_tokens, | ||
| 140 | + next_tokens, | ||
| 141 | + attention_mode, | ||
| 142 | + return_softmax_lse, | ||
| 143 | + sparse_flash_attention_output, | ||
| 144 | + softmax_max, | ||
| 145 | + softmax_sum); | ||
| 146 | + } else { | ||
| 147 | + EXEC_NPU_NO_FORMAT_CHECK_CMD( | ||
| 148 | + aclnnSparseFlashAttention, | ||
| 149 | + query, | ||
| 150 | + key, | ||
| 151 | + value, | ||
| 152 | + sparse_indices, | ||
| 153 | + block_table, | ||
| 154 | + actual_seq_lengths_query, | ||
| 155 | + actual_seq_lengths_kv, | ||
| 156 | + query_rope, | ||
| 157 | + key_rope, | ||
| 158 | + scale_value, | ||
| 159 | + sparse_block_size, | ||
| 160 | + layout_query_ptr, | ||
| 161 | + layout_kv_ptr, | ||
| 162 | + sparse_mode, | ||
| 163 | + pre_tokens, | ||
| 164 | + next_tokens, | ||
| 165 | + attention_mode, | ||
| 166 | + return_softmax_lse, | ||
| 167 | + sparse_flash_attention_output, | ||
| 168 | + softmax_max, | ||
| 169 | + softmax_sum); | ||
| 170 | + } | ||
| 118 | 171 | ||
| 119 | - return std::tuple<at::Tensor, at::Tensor, at::Tensor>(sparse_flash_attention_output, softmax_max, softmax_sum); | 172 | + return std::tuple<at::Tensor, at::Tensor, at::Tensor>(sparse_flash_attention_output, softmax_max, softmax_sum); |
| 120 | } | 173 | } |
| 121 | 174 | ||
| 122 | } // namespace op_api | 175 | } // namespace op_api |
| @@ -26,61 +26,93 @@ const int DIMENSION_3D = 3; | |||
| 26 | const int DIMENSION_4D = 4; | 26 | const int DIMENSION_4D = 4; |
| 27 | 27 | ||
| 28 | std::tuple<at::Tensor, at::Tensor, at::Tensor, at::Tensor> npu_sparse_lightning_indexer_grad_kl_loss_symint( | 28 | std::tuple<at::Tensor, at::Tensor, at::Tensor, at::Tensor> npu_sparse_lightning_indexer_grad_kl_loss_symint( |
| 29 | - const at::Tensor &query, | 29 | + const at::Tensor& query, |
| 30 | - const at::Tensor &key, | 30 | + const at::Tensor& key, |
| 31 | - const at::Tensor &query_index, | 31 | + const at::Tensor& query_index, |
| 32 | - const at::Tensor &key_index, | 32 | + const at::Tensor& key_index, |
| 33 | - const at::Tensor &weights, | 33 | + const at::Tensor& weights, |
| 34 | - const at::Tensor &sparse_indices, | 34 | + const at::Tensor& sparse_indices, |
| 35 | - const at::Tensor &softmax_max, | 35 | + const at::Tensor& softmax_max, |
| 36 | - const at::Tensor &softmax_sum, | 36 | + const at::Tensor& softmax_sum, |
| 37 | double scale_value, | 37 | double scale_value, |
| 38 | - const c10::optional<at::Tensor> &query_rope, | 38 | + const c10::optional<at::Tensor>& query_rope, |
| 39 | - const c10::optional<at::Tensor> &key_rope, | 39 | + const c10::optional<at::Tensor>& key_rope, |
| 40 | c10::OptionalArrayRef<c10::SymInt> actual_seq_qlen, | 40 | c10::OptionalArrayRef<c10::SymInt> actual_seq_qlen, |
| 41 | c10::OptionalArrayRef<c10::SymInt> actual_seq_klen, | 41 | c10::OptionalArrayRef<c10::SymInt> actual_seq_klen, |
| 42 | c10::optional<c10::string_view> layout, | 42 | c10::optional<c10::string_view> layout, |
| 43 | c10::optional<int64_t> sparse_mode, | 43 | c10::optional<int64_t> sparse_mode, |
| 44 | c10::optional<int64_t> pre_tokens, | 44 | c10::optional<int64_t> pre_tokens, |
| 45 | - c10::optional<int64_t> next_tokens) | 45 | + c10::optional<int64_t> next_tokens) { |
| 46 | -{ | 46 | + const at::Tensor& query_rope_const = query_rope.value_or(at::Tensor()); |
| 47 | - const at::Tensor &query_rope_const = query_rope.value_or(at::Tensor()); | 47 | + const at::Tensor& key_rope_const = key_rope.value_or(at::Tensor()); |
| 48 | - const at::Tensor &key_rope_const = key_rope.value_or(at::Tensor()); | 48 | + auto actual_seq_qlen_const = |
| 49 | - auto actual_seq_qlen_const = actual_seq_qlen.has_value() ? c10::asIntArrayRefUnchecked(actual_seq_qlen.value()) : at::IntArrayRef{}; | 49 | + actual_seq_qlen.has_value() ? c10::asIntArrayRefUnchecked(actual_seq_qlen.value()) : at::IntArrayRef{}; |
| 50 | - auto actual_seq_klen_const = actual_seq_klen.has_value() ? c10::asIntArrayRefUnchecked(actual_seq_klen.value()) : at::IntArrayRef{}; | 50 | + auto actual_seq_klen_const = |
| 51 | - c10::string_view layout_str = layout.value_or("BSND"); | 51 | + actual_seq_klen.has_value() ? c10::asIntArrayRefUnchecked(actual_seq_klen.value()) : at::IntArrayRef{}; |
| 52 | - char *layout_ptr = const_cast<char *>(layout_str.data()); | 52 | + c10::string_view layout_str = layout.value_or("BSND"); |
| 53 | - int64_t sparse_mode_const = sparse_mode.value_or(3); | 53 | + char* layout_ptr = const_cast<char*>(layout_str.data()); |
| 54 | - int64_t pre_tokens_const = pre_tokens.value_or(9223372036854775807); | 54 | + int64_t sparse_mode_const = sparse_mode.value_or(3); |
| 55 | - int64_t next_tokens_const = next_tokens.value_or(9223372036854775807); | 55 | + int64_t pre_tokens_const = pre_tokens.value_or(9223372036854775807); |
| 56 | - bool deterministic_const = true; | 56 | + int64_t next_tokens_const = next_tokens.value_or(9223372036854775807); |
| 57 | - TORCH_CHECK(query.dim() == DIMENSION_3D || query.dim() == DIMENSION_4D, | 57 | + bool deterministic_const = true; |
| 58 | - "The shapes of the input query should be 3 or 4 dimensional, but got ", | 58 | + TORCH_CHECK( |
| 59 | - query.dim(), "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 59 | + query.dim() == DIMENSION_3D || query.dim() == DIMENSION_4D, |
| 60 | - if (query_rope_const.defined()) { | 60 | + "The shapes of the input query should be 3 or 4 dimensional, but got ", |
| 61 | - TORCH_CHECK(query_rope_const.dim() == DIMENSION_3D || query_rope_const.dim() == DIMENSION_4D, | 61 | + query.dim(), |
| 62 | - "The shapes of the input query_rope should be 3 or 4 dimensional, but got ", | 62 | + "-dimensional", |
| 63 | - query_rope_const.dim(), "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 63 | + OPS_ERROR(ErrCode::PARAM)); |
| 64 | - } | 64 | + if (query_rope_const.defined()) { |
| 65 | - TORCH_CHECK(key.dim() == DIMENSION_3D || key.dim() == DIMENSION_4D, | 65 | + TORCH_CHECK( |
| 66 | - "The shapes of the input key should be 3 or 4 dimensional, but got ", key.dim(), | 66 | + query_rope_const.dim() == DIMENSION_3D || query_rope_const.dim() == DIMENSION_4D, |
| 67 | - "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 67 | + "The shapes of the input query_rope should be 3 or 4 dimensional, but got ", |
| 68 | - if (key_rope_const.defined()) { | 68 | + query_rope_const.dim(), |
| 69 | - TORCH_CHECK(key_rope_const.dim() == DIMENSION_3D || key_rope_const.dim() == DIMENSION_4D, | 69 | + "-dimensional", |
| 70 | - "The shapes of the input key_rope should be 3 or 4 dimensional, but got ", | 70 | + OPS_ERROR(ErrCode::PARAM)); |
| 71 | - key_rope_const.dim(), "-dimensional", OPS_ERROR(ErrCode::PARAM)); | 71 | + } |
| 72 | - } | 72 | + TORCH_CHECK( |
| 73 | - at::Tensor d_query_index = OpPreparation::apply_tensor_without_format(query_index); | 73 | + key.dim() == DIMENSION_3D || key.dim() == DIMENSION_4D, |
| 74 | - at::Tensor d_key_index = OpPreparation::apply_tensor_without_format(key_index); | 74 | + "The shapes of the input key should be 3 or 4 dimensional, but got ", |
| 75 | - at::Tensor d_weights = OpPreparation::apply_tensor_without_format(weights); | 75 | + key.dim(), |
| 76 | - at::Tensor loss = OpPreparation::apply_tensor_without_format({1}, query.options().dtype(at::kFloat)); | 76 | + "-dimensional", |
| 77 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 78 | + if (key_rope_const.defined()) { | ||
| 79 | + TORCH_CHECK( | ||
| 80 | + key_rope_const.dim() == DIMENSION_3D || key_rope_const.dim() == DIMENSION_4D, | ||
| 81 | + "The shapes of the input key_rope should be 3 or 4 dimensional, but got ", | ||
| 82 | + key_rope_const.dim(), | ||
| 83 | + "-dimensional", | ||
| 84 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 85 | + } | ||
| 86 | + at::Tensor d_query_index = OpPreparation::apply_tensor_without_format(query_index); | ||
| 87 | + at::Tensor d_key_index = OpPreparation::apply_tensor_without_format(key_index); | ||
| 88 | + at::Tensor d_weights = OpPreparation::apply_tensor_without_format(weights); | ||
| 89 | + at::Tensor loss = OpPreparation::apply_tensor_without_format({1}, query.options().dtype(at::kFloat)); | ||
| 77 | 90 | ||
| 78 | - EXEC_NPU_NO_FORMAT_CHECK_CMD( | 91 | + EXEC_NPU_NO_FORMAT_CHECK_CMD( |
| 79 | - aclnnSparseLightningIndexerGradKLLoss, query, key, query_index, key_index, weights, | 92 | + aclnnSparseLightningIndexerGradKLLoss, |
| 80 | - sparse_indices, softmax_max, softmax_sum, query_rope_const, key_rope_const, actual_seq_qlen_const, | 93 | + query, |
| 81 | - actual_seq_klen_const, scale_value, layout_ptr, sparse_mode_const, pre_tokens_const, next_tokens_const, deterministic_const, | 94 | + key, |
| 82 | - d_query_index, d_key_index, d_weights, loss); | 95 | + query_index, |
| 96 | + key_index, | ||
| 97 | + weights, | ||
| 98 | + sparse_indices, | ||
| 99 | + softmax_max, | ||
| 100 | + softmax_sum, | ||
| 101 | + query_rope_const, | ||
| 102 | + key_rope_const, | ||
| 103 | + actual_seq_qlen_const, | ||
| 104 | + actual_seq_klen_const, | ||
| 105 | + scale_value, | ||
| 106 | + layout_ptr, | ||
| 107 | + sparse_mode_const, | ||
| 108 | + pre_tokens_const, | ||
| 109 | + next_tokens_const, | ||
| 110 | + deterministic_const, | ||
| 111 | + d_query_index, | ||
| 112 | + d_key_index, | ||
| 113 | + d_weights, | ||
| 114 | + loss); | ||
| 83 | 115 | ||
| 84 | - return std::make_tuple(d_query_index, d_key_index, d_weights, loss); | 116 | + return std::make_tuple(d_query_index, d_key_index, d_weights, loss); |
| 85 | -} | ||
| 86 | } | 117 | } |
| 118 | +} // namespace op_api | ||
| @@ -21,44 +21,49 @@ | |||
| 21 | namespace op_api { | 21 | namespace op_api { |
| 22 | using npu_preparation = at_npu::native::OpPreparation; | 22 | using npu_preparation = at_npu::native::OpPreparation; |
| 23 | 23 | ||
| 24 | -at::Tensor& std_out(const at::Tensor& self, at::OptionalIntArrayRef dim, | 24 | +at::Tensor& std_out( |
| 25 | - const c10::optional<c10::Scalar>& correction, bool keepdim, at::Tensor& out) | 25 | + const at::Tensor& self, |
| 26 | -{ | 26 | + at::OptionalIntArrayRef dim, |
| 27 | - if (!correction_fits_aclnn_int64(correction)) { | 27 | + const c10::optional<c10::Scalar>& correction, |
| 28 | - at::Tensor cpu_out = out.cpu(); | 28 | + bool keepdim, |
| 29 | - at::std_out(cpu_out, self.cpu(), dim, correction, keepdim); | 29 | + at::Tensor& out) { |
| 30 | - out.copy_(cpu_out); | 30 | + if (!correction_fits_aclnn_int64(correction)) { |
| 31 | - return out; | 31 | + at::Tensor cpu_out = out.cpu(); |
| 32 | - } | 32 | + at::std_out(cpu_out, self.cpu(), dim, correction, keepdim); |
| 33 | - DO_COMPATIBILITY(aclnnStd, acl_op::std_out(self, dim, correction, keepdim, out)); | 33 | + out.copy_(cpu_out); |
| 34 | - c10::SmallVector<int64_t, SIZE> real_dim = op_plugin::utils::get_dimlist_for_tensor(self); | ||
| 35 | - if (dim.has_value()) { | ||
| 36 | - real_dim = op_infer::array_to_small_vector(dim.value()); | ||
| 37 | - } | ||
| 38 | - auto output_size = op_infer::reduce_ops_npu_output_size(self, real_dim, keepdim); | ||
| 39 | - int64_t real_correction = correction.has_value() ? correction.value().toLong() : 1; | ||
| 40 | - auto real_dim_array = at::IntArrayRef(real_dim); | ||
| 41 | - npu_preparation::check_tensor({self}, out, self, output_size); | ||
| 42 | - EXEC_NPU_CMD(aclnnStd, self, real_dim_array, real_correction, keepdim, out); | ||
| 43 | return out; | 34 | return out; |
| 35 | + } | ||
| 36 | + DO_COMPATIBILITY(aclnnStd, acl_op::std_out(self, dim, correction, keepdim, out)); | ||
| 37 | + c10::SmallVector<int64_t, SIZE> real_dim = op_plugin::utils::get_dimlist_for_tensor(self); | ||
| 38 | + if (dim.has_value()) { | ||
| 39 | + real_dim = op_infer::array_to_small_vector(dim.value()); | ||
| 40 | + } | ||
| 41 | + auto output_size = op_infer::reduce_ops_npu_output_size(self, real_dim, keepdim); | ||
| 42 | + int64_t real_correction = correction.has_value() ? correction.value().toLong() : 1; | ||
| 43 | + auto real_dim_array = at::IntArrayRef(real_dim); | ||
| 44 | + npu_preparation::check_tensor({self}, out, self, output_size); | ||
| 45 | + EXEC_NPU_CMD(aclnnStd, self, real_dim_array, real_correction, keepdim, out); | ||
| 46 | + return out; | ||
| 44 | } | 47 | } |
| 45 | 48 | ||
| 46 | -at::Tensor std(const at::Tensor& self, at::OptionalIntArrayRef dim, | 49 | +at::Tensor std( |
| 47 | - const c10::optional<c10::Scalar>& correction, bool keepdim) | 50 | + const at::Tensor& self, |
| 48 | -{ | 51 | + at::OptionalIntArrayRef dim, |
| 49 | - if (!correction_fits_aclnn_int64(correction)) { | 52 | + const c10::optional<c10::Scalar>& correction, |
| 50 | - return at::std(self.cpu(), dim, correction, keepdim).to(self.options()); | 53 | + bool keepdim) { |
| 51 | - } | 54 | + if (!correction_fits_aclnn_int64(correction)) { |
| 52 | - DO_COMPATIBILITY(aclnnStd, acl_op::std(self, dim, correction, keepdim)); | 55 | + return at::std(self.cpu(), dim, correction, keepdim).to(self.options()); |
| 53 | - c10::SmallVector<int64_t, SIZE> real_dim = op_plugin::utils::get_dimlist_for_tensor(self); | 56 | + } |
| 54 | - if (dim.has_value()) { | 57 | + DO_COMPATIBILITY(aclnnStd, acl_op::std(self, dim, correction, keepdim)); |
| 55 | - real_dim = op_infer::array_to_small_vector(dim.value()); | 58 | + c10::SmallVector<int64_t, SIZE> real_dim = op_plugin::utils::get_dimlist_for_tensor(self); |
| 56 | - } | 59 | + if (dim.has_value()) { |
| 57 | - auto output_size = op_infer::reduce_ops_npu_output_size(self, real_dim, keepdim); | 60 | + real_dim = op_infer::array_to_small_vector(dim.value()); |
| 58 | - auto result = npu_preparation::apply_tensor_without_format(output_size, self.options()); | 61 | + } |
| 59 | - int64_t real_correction = correction.has_value() ? correction.value().toLong() : 1; | 62 | + auto output_size = op_infer::reduce_ops_npu_output_size(self, real_dim, keepdim); |
| 60 | - auto real_dim_array = at::IntArrayRef(real_dim); | 63 | + auto result = npu_preparation::apply_tensor_without_format(output_size, self.options()); |
| 61 | - EXEC_NPU_CMD(aclnnStd, self, real_dim_array, real_correction, keepdim, result); | 64 | + int64_t real_correction = correction.has_value() ? correction.value().toLong() : 1; |
| 62 | - return result; | 65 | + auto real_dim_array = at::IntArrayRef(real_dim); |
| 66 | + EXEC_NPU_CMD(aclnnStd, self, real_dim_array, real_correction, keepdim, result); | ||
| 67 | + return result; | ||
| 63 | } | 68 | } |
| 64 | } // namespace op_api | 69 | } // namespace op_api |
| @@ -24,27 +24,24 @@ std::tuple<at::Tensor, at::Tensor> std_mean( | |||
| 24 | const at::Tensor& self, | 24 | const at::Tensor& self, |
| 25 | at::OptionalIntArrayRef dim, | 25 | at::OptionalIntArrayRef dim, |
| 26 | const c10::optional<at::Scalar>& correction, | 26 | const c10::optional<at::Scalar>& correction, |
| 27 | - bool keepdim) | 27 | + bool keepdim) { |
| 28 | -{ | 28 | + if (!correction_fits_aclnn_int64(correction)) { |
| 29 | - if (!correction_fits_aclnn_int64(correction)) { | 29 | + auto cpu_tup = at::std_mean(self.cpu(), dim, correction, keepdim); |
| 30 | - auto cpu_tup = at::std_mean(self.cpu(), dim, correction, keepdim); | 30 | + return std::make_tuple(std::get<0>(cpu_tup).to(self.options()), std::get<1>(cpu_tup).to(self.options())); |
| 31 | - return std::make_tuple( | 31 | + } |
| 32 | - std::get<0>(cpu_tup).to(self.options()), | 32 | + DO_COMPATIBILITY(aclnnStdMeanCorrection, acl_op::std_mean(self, dim, correction, keepdim)); |
| 33 | - std::get<1>(cpu_tup).to(self.options())); | 33 | + c10::SmallVector<int64_t, SIZE> real_dim = op_plugin::utils::get_dimlist_for_tensor(self); |
| 34 | - } | 34 | + if (dim.has_value()) { |
| 35 | - DO_COMPATIBILITY(aclnnStdMeanCorrection, acl_op::std_mean(self, dim, correction, keepdim)); | 35 | + real_dim = op_infer::array_to_small_vector(dim.value()); |
| 36 | - c10::SmallVector<int64_t, SIZE> real_dim = op_plugin::utils::get_dimlist_for_tensor(self); | 36 | + } |
| 37 | - if (dim.has_value()) { | 37 | + auto output_size = op_infer::reduce_ops_npu_output_size(self, real_dim, keepdim); |
| 38 | - real_dim = op_infer::array_to_small_vector(dim.value()); | ||
| 39 | - } | ||
| 40 | - auto output_size = op_infer::reduce_ops_npu_output_size(self, real_dim, keepdim); | ||
| 41 | 38 | ||
| 42 | - at::Tensor std_out = npu_preparation::apply_tensor_without_format(self, output_size); | 39 | + at::Tensor std_out = npu_preparation::apply_tensor_without_format(self, output_size); |
| 43 | - at::Tensor mean_out = npu_preparation::apply_tensor_without_format(self, output_size); | 40 | + at::Tensor mean_out = npu_preparation::apply_tensor_without_format(self, output_size); |
| 44 | 41 | ||
| 45 | - int64_t real_correction = correction.has_value() ? correction.value().toLong() : 1; | 42 | + int64_t real_correction = correction.has_value() ? correction.value().toLong() : 1; |
| 46 | - auto real_dim_array = at::IntArrayRef(real_dim); | 43 | + auto real_dim_array = at::IntArrayRef(real_dim); |
| 47 | - EXEC_NPU_CMD(aclnnStdMeanCorrection, self, real_dim_array, real_correction, keepdim, std_out, mean_out); | 44 | + EXEC_NPU_CMD(aclnnStdMeanCorrection, self, real_dim_array, real_correction, keepdim, std_out, mean_out); |
| 48 | - return std::tie(std_out, mean_out); | 45 | + return std::tie(std_out, mean_out); |
| 49 | } | 46 | } |
| 50 | } // namespace op_api | 47 | } // namespace op_api |
| @@ -20,115 +20,113 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -inline void alpha_check_npu_tensor(const at::ScalarType self_dtype, const at::ScalarType other_dtype, at::Scalar alpha) | 23 | +inline void alpha_check_npu_tensor( |
| 24 | -{ | 24 | + const at::ScalarType self_dtype, |
| 25 | - TORCH_CHECK(isFloatingType(self_dtype) || isComplexType(self_dtype) || | 25 | + const at::ScalarType other_dtype, |
| 26 | - isFloatingType(other_dtype) || isComplexType(other_dtype) || alpha.isIntegral(true), | 26 | + at::Scalar alpha) { |
| 27 | - "For integral input tensors, argument alpha must not be a floating point number.", | 27 | + TORCH_CHECK( |
| 28 | - OPS_ERROR(ErrCode::TYPE)); | 28 | + isFloatingType(self_dtype) || isComplexType(self_dtype) || isFloatingType(other_dtype) || |
| 29 | + isComplexType(other_dtype) || alpha.isIntegral(true), | ||
| 30 | + "For integral input tensors, argument alpha must not be a floating point number.", | ||
| 31 | + OPS_ERROR(ErrCode::TYPE)); | ||
| 29 | } | 32 | } |
| 30 | 33 | ||
| 31 | -inline void alpha_check_npu_scalar(const at::ScalarType self_dtype, at::Scalar other, at::Scalar alpha) | 34 | +inline void alpha_check_npu_scalar(const at::ScalarType self_dtype, at::Scalar other, at::Scalar alpha) { |
| 32 | -{ | 35 | + TORCH_CHECK( |
| 33 | - TORCH_CHECK(isFloatingType(self_dtype) || isComplexType(self_dtype) || | 36 | + isFloatingType(self_dtype) || isComplexType(self_dtype) || other.isFloatingPoint() || alpha.isIntegral(true), |
| 34 | - other.isFloatingPoint() || alpha.isIntegral(true), | 37 | + "For integral input tensors, argument alpha must not be a floating point number.", |
| 35 | - "For integral input tensors, argument alpha must not be a floating point number.", | 38 | + OPS_ERROR(ErrCode::TYPE)); |
| 36 | - OPS_ERROR(ErrCode::TYPE)); | ||
| 37 | } | 39 | } |
| 38 | 40 | ||
| 39 | -static at::Tensor &sub_out_npu_nocheck(const at::Tensor &self, const at::Tensor &other, const at::Scalar alpha, | 41 | +static at::Tensor& sub_out_npu_nocheck( |
| 40 | - at::Tensor &result) | 42 | + const at::Tensor& self, |
| 41 | -{ | 43 | + const at::Tensor& other, |
| 42 | - if (npu_preparation::IsCPUScalar(other)) { | 44 | + const at::Scalar alpha, |
| 43 | - c10::Scalar other_scalar = other.item(); | 45 | + at::Tensor& result) { |
| 44 | - EXEC_NPU_CMD(aclnnSubs, self, other_scalar, alpha, result); | 46 | + if (npu_preparation::IsCPUScalar(other)) { |
| 45 | - } else { | 47 | + c10::Scalar other_scalar = other.item(); |
| 46 | - EXEC_NPU_CMD(aclnnSub, self, other, alpha, result); | 48 | + EXEC_NPU_CMD(aclnnSubs, self, other_scalar, alpha, result); |
| 47 | - } | 49 | + } else { |
| 48 | - return result; | 50 | + EXEC_NPU_CMD(aclnnSub, self, other, alpha, result); |
| 51 | + } | ||
| 52 | + return result; | ||
| 49 | } | 53 | } |
| 50 | 54 | ||
| 51 | -static at::Tensor& inplace_sub_out_npu_no_check(at::Tensor& self, const at::Tensor& other, const at::Scalar& alpha) | 55 | +static at::Tensor& inplace_sub_out_npu_no_check(at::Tensor& self, const at::Tensor& other, const at::Scalar& alpha) { |
| 52 | -{ | 56 | + if (npu_preparation::IsCPUScalar(other)) { |
| 53 | - if (npu_preparation::IsCPUScalar(other)) { | 57 | + c10::Scalar other_scalar = other.item(); |
| 54 | - c10::Scalar other_scalar = other.item(); | 58 | + EXEC_NPU_CMD(aclnnInplaceSubs, self, other_scalar, alpha); |
| 55 | - EXEC_NPU_CMD(aclnnInplaceSubs, self, other_scalar, alpha); | 59 | + } else { |
| 56 | - } else { | 60 | + EXEC_NPU_CMD(aclnnInplaceSub, self, other, alpha); |
| 57 | - EXEC_NPU_CMD(aclnnInplaceSub, self, other, alpha); | 61 | + } |
| 58 | - } | 62 | + return self; |
| 59 | - return self; | ||
| 60 | } | 63 | } |
| 61 | 64 | ||
| 62 | -static at::Tensor self_tensor_to_device(const at::Tensor &tensor, const at::ScalarType result_type, | 65 | +static at::Tensor self_tensor_to_device( |
| 63 | - const c10::Device device) | 66 | + const at::Tensor& tensor, |
| 64 | -{ | 67 | + const at::ScalarType result_type, |
| 65 | - if (npu_preparation::is_scalar_wrapped_to_tensor(tensor)) { | 68 | + const c10::Device device) { |
| 66 | - at::Scalar scalar = tensor.item(); | 69 | + if (npu_preparation::is_scalar_wrapped_to_tensor(tensor)) { |
| 67 | - return npu_preparation::copy_scalar_to_device(scalar, result_type, device); | 70 | + at::Scalar scalar = tensor.item(); |
| 68 | - } | 71 | + return npu_preparation::copy_scalar_to_device(scalar, result_type, device); |
| 69 | - return tensor; | 72 | + } |
| 73 | + return tensor; | ||
| 70 | } | 74 | } |
| 71 | 75 | ||
| 72 | -static at::Tensor sub_dest_output(const at::Tensor& self, const at::Tensor& other) | 76 | +static at::Tensor sub_dest_output(const at::Tensor& self, const at::Tensor& other) { |
| 73 | -{ | 77 | + bool is_self_wrapped = npu_preparation::is_scalar_wrapped_to_tensor(self); |
| 74 | - bool is_self_wrapped = npu_preparation::is_scalar_wrapped_to_tensor(self); | 78 | + return is_self_wrapped ? other : self; |
| 75 | - return is_self_wrapped ? other : self; | ||
| 76 | } | 79 | } |
| 77 | 80 | ||
| 78 | -at::Tensor &sub_out(const at::Tensor &self, const at::Tensor &other, const at::Scalar &alpha, at::Tensor &result) | 81 | +at::Tensor& sub_out(const at::Tensor& self, const at::Tensor& other, const at::Scalar& alpha, at::Tensor& result) { |
| 79 | -{ | 82 | + DO_COMPATIBILITY(aclnnSub, acl_op::sub_out(self, other, alpha, result)); |
| 80 | - DO_COMPATIBILITY(aclnnSub, acl_op::sub_out(self, other, alpha, result)); | 83 | + DO_COMPATIBILITY(aclnnSubs, acl_op::sub_out(self, other, alpha, result)); |
| 81 | - DO_COMPATIBILITY(aclnnSubs, acl_op::sub_out(self, other, alpha, result)); | 84 | + alpha_check_npu_tensor(self.scalar_type(), other.scalar_type(), alpha); |
| 82 | - alpha_check_npu_tensor(self.scalar_type(), other.scalar_type(), alpha); | 85 | + auto output_size = op_infer::broadcast_ops_npu_output_size(self, other); |
| 83 | - auto output_size = op_infer::broadcast_ops_npu_output_size(self, other); | 86 | + at::ScalarType result_type = at::native::result_type(self, other); |
| 84 | - at::ScalarType result_type = at::native::result_type(self, other); | 87 | + at::Tensor self_converted = self_tensor_to_device(self, result_type, result.device()); |
| 85 | - at::Tensor self_converted = self_tensor_to_device(self, result_type, result.device()); | 88 | + npu_preparation::check_tensor({self}, result, result, output_size); |
| 86 | - npu_preparation::check_tensor({self}, result, result, output_size); | 89 | + npu_preparation::check_memory({self, other}, {result}); |
| 87 | - npu_preparation::check_memory({self, other}, {result}); | 90 | + sub_out_npu_nocheck(self_converted, other, alpha, result); |
| 88 | - sub_out_npu_nocheck(self_converted, other, alpha, result); | 91 | + return result; |
| 89 | - return result; | ||
| 90 | } | 92 | } |
| 91 | 93 | ||
| 92 | -at::Tensor sub(const at::Tensor &self, const at::Tensor &other, const at::Scalar &alpha) | 94 | +at::Tensor sub(const at::Tensor& self, const at::Tensor& other, const at::Scalar& alpha) { |
| 93 | -{ | 95 | + DO_COMPATIBILITY(aclnnSub, acl_op::sub(self, other, alpha)); |
| 94 | - DO_COMPATIBILITY(aclnnSub, acl_op::sub(self, other, alpha)); | 96 | + DO_COMPATIBILITY(aclnnSubs, acl_op::sub(self, other, alpha)); |
| 95 | - DO_COMPATIBILITY(aclnnSubs, acl_op::sub(self, other, alpha)); | 97 | + alpha_check_npu_tensor(self.scalar_type(), other.scalar_type(), alpha); |
| 96 | - alpha_check_npu_tensor(self.scalar_type(), other.scalar_type(), alpha); | 98 | + at::Tensor output_tensor = sub_dest_output(self, other); |
| 97 | - at::Tensor output_tensor = sub_dest_output(self, other); | 99 | + auto output_size = op_infer::broadcast_ops_npu_output_size(self, other); |
| 98 | - auto output_size = op_infer::broadcast_ops_npu_output_size(self, other); | 100 | + at::ScalarType result_type = at::native::result_type(self, other); |
| 99 | - at::ScalarType result_type = at::native::result_type(self, other); | 101 | + at::Tensor self_converted = self_tensor_to_device(self, result_type, output_tensor.device()); |
| 100 | - at::Tensor self_converted = self_tensor_to_device(self, result_type, output_tensor.device()); | 102 | + auto result = npu_preparation::apply_tensor_without_format(output_size, output_tensor.options().dtype(result_type)); |
| 101 | - auto result = npu_preparation::apply_tensor_without_format(output_size, output_tensor.options().dtype(result_type)); | 103 | + sub_out_npu_nocheck(self_converted, other, alpha, result); |
| 102 | - sub_out_npu_nocheck(self_converted, other, alpha, result); | 104 | + return result; |
| 103 | - return result; | ||
| 104 | } | 105 | } |
| 105 | 106 | ||
| 106 | -at::Tensor sub(const at::Tensor &self, const at::Scalar &other, const at::Scalar &alpha) | 107 | +at::Tensor sub(const at::Tensor& self, const at::Scalar& other, const at::Scalar& alpha) { |
| 107 | -{ | 108 | + DO_COMPATIBILITY(aclnnSubs, acl_op::sub(self, other, alpha)); |
| 108 | - DO_COMPATIBILITY(aclnnSubs, acl_op::sub(self, other, alpha)); | 109 | + alpha_check_npu_scalar(self.scalar_type(), other, alpha); |
| 109 | - alpha_check_npu_scalar(self.scalar_type(), other, alpha); | 110 | + auto output_size = op_infer::input_same_output_size(self); |
| 110 | - auto output_size = op_infer::input_same_output_size(self); | 111 | + at::ScalarType result_type = at::native::result_type(self, other); |
| 111 | - at::ScalarType result_type = at::native::result_type(self, other); | 112 | + auto result = npu_preparation::apply_tensor_without_format(output_size, self.options().dtype(result_type)); |
| 112 | - auto result = npu_preparation::apply_tensor_without_format(output_size, self.options().dtype(result_type)); | 113 | + EXEC_NPU_CMD(aclnnSubs, self, other, alpha, result); |
| 113 | - EXEC_NPU_CMD(aclnnSubs, self, other, alpha, result); | 114 | + return result; |
| 114 | - return result; | ||
| 115 | } | 115 | } |
| 116 | 116 | ||
| 117 | -at::Tensor &sub_(at::Tensor &self, const at::Tensor &other, const at::Scalar &alpha) | 117 | +at::Tensor& sub_(at::Tensor& self, const at::Tensor& other, const at::Scalar& alpha) { |
| 118 | -{ | 118 | + DO_COMPATIBILITY(aclnnInplaceSub, acl_op::sub_(self, other, alpha)); |
| 119 | - DO_COMPATIBILITY(aclnnInplaceSub, acl_op::sub_(self, other, alpha)); | 119 | + DO_COMPATIBILITY(aclnnInplaceSubs, acl_op::sub_(self, other, alpha)); |
| 120 | - DO_COMPATIBILITY(aclnnInplaceSubs, acl_op::sub_(self, other, alpha)); | 120 | + alpha_check_npu_tensor(self.scalar_type(), other.scalar_type(), alpha); |
| 121 | - alpha_check_npu_tensor(self.scalar_type(), other.scalar_type(), alpha); | 121 | + npu_preparation::check_memory({self, other}, {self}); |
| 122 | - npu_preparation::check_memory({self, other}, {self}); | 122 | + inplace_sub_out_npu_no_check(self, other, alpha); |
| 123 | - inplace_sub_out_npu_no_check(self, other, alpha); | 123 | + return self; |
| 124 | - return self; | ||
| 125 | } | 124 | } |
| 126 | 125 | ||
| 127 | -at::Tensor &sub_(at::Tensor &self, const at::Scalar &other, const at::Scalar &alpha) | 126 | +at::Tensor& sub_(at::Tensor& self, const at::Scalar& other, const at::Scalar& alpha) { |
| 128 | -{ | 127 | + DO_COMPATIBILITY(aclnnInplaceSubs, acl_op::sub_(self, other, alpha)); |
| 129 | - DO_COMPATIBILITY(aclnnInplaceSubs, acl_op::sub_(self, other, alpha)); | 128 | + alpha_check_npu_scalar(self.scalar_type(), other, alpha); |
| 130 | - alpha_check_npu_scalar(self.scalar_type(), other, alpha); | 129 | + EXEC_NPU_CMD(aclnnInplaceSubs, self, other, alpha); |
| 131 | - EXEC_NPU_CMD(aclnnInplaceSubs, self, other, alpha); | 130 | + return self; |
| 132 | - return self; | ||
| 133 | -} | ||
| 134 | } | 131 | } |
| 132 | +} // namespace op_api | ||
| @@ -21,46 +21,41 @@ | |||
| 21 | namespace op_api { | 21 | namespace op_api { |
| 22 | 22 | ||
| 23 | 23 | ||
| 24 | -at::Tensor& sum_out(const at::Tensor &self, | 24 | +at::Tensor& sum_out( |
| 25 | - at::DimnameList dim, | 25 | + const at::Tensor& self, |
| 26 | - bool keepdim, | 26 | + at::DimnameList dim, |
| 27 | - c10::optional<c10::ScalarType> dtype, | 27 | + bool keepdim, |
| 28 | - at::Tensor &result) | 28 | + c10::optional<c10::ScalarType> dtype, |
| 29 | -{ | 29 | + at::Tensor& result) { |
| 30 | - DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum_out(self, dim, keepdim, dtype, result)); | 30 | + DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum_out(self, dim, keepdim, dtype, result)); |
| 31 | - return op_api::sum_out(self, dimnames_to_positions(self, dim), keepdim, dtype, result); | 31 | + return op_api::sum_out(self, dimnames_to_positions(self, dim), keepdim, dtype, result); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | -at::Tensor sum(const at::Tensor &self, | 34 | +at::Tensor sum(const at::Tensor& self, at::DimnameList dim, bool keepdim, c10::optional<c10::ScalarType> dtype) { |
| 35 | - at::DimnameList dim, | 35 | + DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum(self, dim, keepdim, dtype)); |
| 36 | - bool keepdim, | 36 | + return op_api::sum(self, dimnames_to_positions(self, dim), keepdim, dtype); |
| 37 | - c10::optional<c10::ScalarType> dtype) | ||
| 38 | -{ | ||
| 39 | - DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum(self, dim, keepdim, dtype)); | ||
| 40 | - return op_api::sum(self, dimnames_to_positions(self, dim), keepdim, dtype); | ||
| 41 | } | 37 | } |
| 42 | 38 | ||
| 43 | 39 | ||
| 44 | -at::Tensor sum(const at::Tensor &self, c10::optional<c10::ScalarType> dtype) | 40 | +at::Tensor sum(const at::Tensor& self, c10::optional<c10::ScalarType> dtype) { |
| 45 | -{ | 41 | + DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum(self, dtype)); |
| 46 | - DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum(self, dtype)); | 42 | + return op_api::sum(self, c10::SmallVector<int64_t, N>{}, false, dtype); |
| 47 | - return op_api::sum(self, c10::SmallVector<int64_t, N>{}, false, dtype); | ||
| 48 | } | 43 | } |
| 49 | 44 | ||
| 50 | -at::Tensor& sum_out(const at::Tensor &self, | 45 | +at::Tensor& sum_out( |
| 51 | - at::OptionalIntArrayRef dim, | 46 | + const at::Tensor& self, |
| 52 | - bool keepdim, | 47 | + at::OptionalIntArrayRef dim, |
| 53 | - c10::optional<c10::ScalarType> dtype, | 48 | + bool keepdim, |
| 54 | - at::Tensor &result) | 49 | + c10::optional<c10::ScalarType> dtype, |
| 55 | -{ | 50 | + at::Tensor& result) { |
| 56 | - return op_api::sum_out_common_nocheck(self, dim.value_or(at::IntArrayRef{}), keepdim, dtype, result); | 51 | + return op_api::sum_out_common_nocheck(self, dim.value_or(at::IntArrayRef{}), keepdim, dtype, result); |
| 57 | } | 52 | } |
| 58 | 53 | ||
| 59 | -at::Tensor sum(const at::Tensor &self, | 54 | +at::Tensor sum( |
| 60 | - at::OptionalIntArrayRef dim, | 55 | + const at::Tensor& self, |
| 61 | - bool keepdim, | 56 | + at::OptionalIntArrayRef dim, |
| 62 | - c10::optional<c10::ScalarType> dtype) | 57 | + bool keepdim, |
| 63 | -{ | 58 | + c10::optional<c10::ScalarType> dtype) { |
| 64 | - return op_api::sum_common_nocheck(self, dim.value_or(at::IntArrayRef{}), keepdim, dtype); | 59 | + return op_api::sum_common_nocheck(self, dim.value_or(at::IntArrayRef{}), keepdim, dtype); |
| 65 | -} | ||
| 66 | } | 60 | } |
| 61 | +} // namespace op_api | ||
| @@ -33,76 +33,95 @@ std::tuple<at::Tensor, at::Tensor, at::Tensor, at::Tensor> _npu_swiglu_backward_ | |||
| 33 | c10::string_view round_mode, | 33 | c10::string_view round_mode, |
| 34 | int64_t scale_alg, | 34 | int64_t scale_alg, |
| 35 | int64_t dst_type, | 35 | int64_t dst_type, |
| 36 | - double dst_type_max) | 36 | + double dst_type_max) { |
| 37 | -{ | 37 | + TORCH_CHECK(x.dim() >= MIN_INPUT_DIM, "The input x should be at least 2D" + OPS_ERROR(ErrCode::PARAM)); |
| 38 | - TORCH_CHECK(x.dim() >= MIN_INPUT_DIM, "The input x should be at least 2D" + OPS_ERROR(ErrCode::PARAM)); | 38 | + TORCH_CHECK( |
| 39 | - TORCH_CHECK(x.size(-1) % SPLIT_BLOCK_SIZE == 0 && x.size(-1) > 0, "The last dim of input must be divisible by 64 " | 39 | + x.size(-1) % SPLIT_BLOCK_SIZE == 0 && x.size(-1) > 0, |
| 40 | - "and more than 0." + OPS_ERROR(ErrCode::PARAM)); | 40 | + "The last dim of input must be divisible by 64 " |
| 41 | + "and more than 0." + | ||
| 42 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 41 | 43 | ||
| 42 | - static const bool is_available = check_aclnn_kernel_available("aclnnSwigluBackwardMxQuantWithDualAxis"); | 44 | + static const bool is_available = check_aclnn_kernel_available("aclnnSwigluBackwardMxQuantWithDualAxis"); |
| 43 | - TORCH_CHECK(is_available, | 45 | + TORCH_CHECK( |
| 44 | - "Current CANN version do not support this api: _npu_swiglu_backward_mx_quant_with_dual_axis. " | 46 | + is_available, |
| 45 | - "Please try to update the version of CANN." + OPS_ERROR(ErrCode::PARAM)); | 47 | + "Current CANN version do not support this api: _npu_swiglu_backward_mx_quant_with_dual_axis. " |
| 48 | + "Please try to update the version of CANN." + | ||
| 49 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 46 | 50 | ||
| 47 | - const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); | 51 | + const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); |
| 48 | - char *round_mode_ptr = const_cast<char *>(round_mode.data()); | 52 | + char* round_mode_ptr = const_cast<char*>(round_mode.data()); |
| 49 | - // y1_out and y2_out have the same shape as x | 53 | + // y1_out and y2_out have the same shape as x |
| 50 | - auto x_grad_shape = op_infer::array_to_small_vector(x.sizes()); | 54 | + auto x_grad_shape = op_infer::array_to_small_vector(x.sizes()); |
| 51 | 55 | ||
| 52 | - // Infer mxscale1 shape: ceil(last_dim / 64) + append 2 | 56 | + // Infer mxscale1 shape: ceil(last_dim / 64) + append 2 |
| 53 | - auto mxscale1_shape = op_infer::array_to_small_vector(x.sizes()); | 57 | + auto mxscale1_shape = op_infer::array_to_small_vector(x.sizes()); |
| 54 | - int64_t last_dim = x.size(-1); | 58 | + int64_t last_dim = x.size(-1); |
| 55 | - mxscale1_shape[mxscale1_shape.size() - 1] = | 59 | + mxscale1_shape[mxscale1_shape.size() - 1] = |
| 56 | - static_cast<int64_t>(std::ceil(static_cast<double>(last_dim) / SPLIT_BLOCK_SIZE)); | 60 | + static_cast<int64_t>(std::ceil(static_cast<double>(last_dim) / SPLIT_BLOCK_SIZE)); |
| 57 | - mxscale1_shape.emplace_back(NUM_TWO); | 61 | + mxscale1_shape.emplace_back(NUM_TWO); |
| 58 | 62 | ||
| 59 | - // Infer mxscale2 shape | 63 | + // Infer mxscale2 shape |
| 60 | - auto mxscale2_shape = op_infer::array_to_small_vector(x.sizes()); | 64 | + auto mxscale2_shape = op_infer::array_to_small_vector(x.sizes()); |
| 61 | - int64_t second_to_last_dim = x.size(-2); | 65 | + int64_t second_to_last_dim = x.size(-2); |
| 62 | - int64_t quant_size = static_cast<int64_t>(std::ceil(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)); | 66 | + int64_t quant_size = static_cast<int64_t>(std::ceil(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)); |
| 63 | - if (group_index_opt.defined()) { | 67 | + if (group_index_opt.defined()) { |
| 64 | - quant_size = static_cast<int64_t>(std::floor(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)) | 68 | + quant_size = static_cast<int64_t>(std::floor(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)) + |
| 65 | - + group_index_opt.size(0); | 69 | + group_index_opt.size(0); |
| 66 | - } | 70 | + } |
| 67 | - mxscale2_shape[mxscale2_shape.size() - 2] = quant_size; | 71 | + mxscale2_shape[mxscale2_shape.size() - 2] = quant_size; |
| 68 | - mxscale2_shape.emplace_back(NUM_TWO); | 72 | + mxscale2_shape.emplace_back(NUM_TWO); |
| 69 | 73 | ||
| 70 | - aclDataType x_acltype = c10_npu::GetAclDataType(dst_type); | 74 | + aclDataType x_acltype = c10_npu::GetAclDataType(dst_type); |
| 71 | - ASCEND_LOGI("[npu_swiglu_backward_mx_quant_with_dual_axis]: " | 75 | + ASCEND_LOGI( |
| 72 | - "Getting aclTensor y1_out and y2_out dtype by Parameter(dst_type): %ld", dst_type); | 76 | + "[npu_swiglu_backward_mx_quant_with_dual_axis]: " |
| 77 | + "Getting aclTensor y1_out and y2_out dtype by Parameter(dst_type): %ld", | ||
| 78 | + dst_type); | ||
| 73 | 79 | ||
| 74 | - bool special_output_type = (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || | 80 | + bool special_output_type = |
| 75 | - dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)); | 81 | + (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || |
| 82 | + dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)); | ||
| 76 | 83 | ||
| 77 | - at::Tensor y1_out; | 84 | + at::Tensor y1_out; |
| 78 | - at::Tensor y2_out; | 85 | + at::Tensor y2_out; |
| 79 | - if (special_output_type) { | 86 | + if (special_output_type) { |
| 80 | - int64_t x_last_dim_val = x_grad_shape[x_grad_shape.size() - 1]; | 87 | + int64_t x_last_dim_val = x_grad_shape[x_grad_shape.size() - 1]; |
| 81 | - TORCH_CHECK(x_last_dim_val % NUM_TWO == 0, | 88 | + TORCH_CHECK( |
| 82 | - "The last dim of x_grad must be divisible by 2 if dtype is float4_e2m1 or float4_e1m2" | 89 | + x_last_dim_val % NUM_TWO == 0, |
| 83 | - + OPS_ERROR(ErrCode::PARAM)); | 90 | + "The last dim of x_grad must be divisible by 2 if dtype is float4_e2m1 or float4_e1m2" + |
| 84 | - x_grad_shape[x_grad_shape.size() - 1] = x_last_dim_val / NUM_TWO; | 91 | + OPS_ERROR(ErrCode::PARAM)); |
| 85 | - y1_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::ScalarType::Byte); | 92 | + x_grad_shape[x_grad_shape.size() - 1] = x_last_dim_val / NUM_TWO; |
| 86 | - y2_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::ScalarType::Byte); | 93 | + y1_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::ScalarType::Byte); |
| 87 | - } else { | 94 | + y2_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::ScalarType::Byte); |
| 88 | - at::ScalarType scalar_dtype = npu_preparation::convert_to_scalar_type(x_acltype); | 95 | + } else { |
| 89 | - y1_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::dtype(scalar_dtype)); | 96 | + at::ScalarType scalar_dtype = npu_preparation::convert_to_scalar_type(x_acltype); |
| 90 | - y2_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::dtype(scalar_dtype)); | 97 | + y1_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::dtype(scalar_dtype)); |
| 91 | - } | 98 | + y2_out = npu_preparation::apply_tensor_without_format(x_grad_shape, c10::dtype(scalar_dtype)); |
| 99 | + } | ||
| 92 | 100 | ||
| 93 | - at::Tensor mxscale1 = npu_preparation::apply_tensor_without_format(mxscale1_shape, c10::dtype(at::ScalarType::Byte)); | 101 | + at::Tensor mxscale1 = npu_preparation::apply_tensor_without_format(mxscale1_shape, c10::dtype(at::ScalarType::Byte)); |
| 94 | - at::Tensor mxscale2 = npu_preparation::apply_tensor_without_format(mxscale2_shape, c10::dtype(at::ScalarType::Byte)); | 102 | + at::Tensor mxscale2 = npu_preparation::apply_tensor_without_format(mxscale2_shape, c10::dtype(at::ScalarType::Byte)); |
| 95 | 103 | ||
| 96 | - TensorWrapper y1_out_wrapper = {y1_out, x_acltype}; | 104 | + TensorWrapper y1_out_wrapper = {y1_out, x_acltype}; |
| 97 | - TensorWrapper y2_out_wrapper = {y2_out, x_acltype}; | 105 | + TensorWrapper y2_out_wrapper = {y2_out, x_acltype}; |
| 98 | - TensorWrapper mxscale1_wrapper = {mxscale1, aclDataType::ACL_FLOAT8_E8M0}; | 106 | + TensorWrapper mxscale1_wrapper = {mxscale1, aclDataType::ACL_FLOAT8_E8M0}; |
| 99 | - TensorWrapper mxscale2_wrapper = {mxscale2, aclDataType::ACL_FLOAT8_E8M0}; | 107 | + TensorWrapper mxscale2_wrapper = {mxscale2, aclDataType::ACL_FLOAT8_E8M0}; |
| 100 | 108 | ||
| 101 | - EXEC_NPU_CMD(aclnnSwigluBackwardMxQuantWithDualAxis, x, y_grad, group_index_opt, activate_left, | 109 | + EXEC_NPU_CMD( |
| 102 | - round_mode_ptr, scale_alg, x_acltype, dst_type_max, | 110 | + aclnnSwigluBackwardMxQuantWithDualAxis, |
| 103 | - y1_out_wrapper, mxscale1_wrapper, y2_out_wrapper, mxscale2_wrapper); | 111 | + x, |
| 112 | + y_grad, | ||
| 113 | + group_index_opt, | ||
| 114 | + activate_left, | ||
| 115 | + round_mode_ptr, | ||
| 116 | + scale_alg, | ||
| 117 | + x_acltype, | ||
| 118 | + dst_type_max, | ||
| 119 | + y1_out_wrapper, | ||
| 120 | + mxscale1_wrapper, | ||
| 121 | + y2_out_wrapper, | ||
| 122 | + mxscale2_wrapper); | ||
| 104 | 123 | ||
| 105 | - return std::make_tuple(y1_out, mxscale1, y2_out, mxscale2); | 124 | + return std::make_tuple(y1_out, mxscale1, y2_out, mxscale2); |
| 106 | } | 125 | } |
| 107 | 126 | ||
| 108 | } // namespace op_api | 127 | } // namespace op_api |
| @@ -20,27 +20,29 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -std::tuple<at::Tensor, at::Tensor> npu_swiglu_group_quant_backward(const at::Tensor &grad_y, const at::Tensor &x, | 23 | +std::tuple<at::Tensor, at::Tensor> npu_swiglu_group_quant_backward( |
| 24 | - const c10::optional<at::Tensor> &weight, const c10::optional<at::Tensor> &y_origin, | 24 | + const at::Tensor& grad_y, |
| 25 | - const c10::optional<at::Tensor> &group_index, double clamp_limit) | 25 | + const at::Tensor& x, |
| 26 | -{ | 26 | + const c10::optional<at::Tensor>& weight, |
| 27 | + const c10::optional<at::Tensor>& y_origin, | ||
| 28 | + const c10::optional<at::Tensor>& group_index, | ||
| 29 | + double clamp_limit) { | ||
| 30 | + // check x last dim | ||
| 31 | + int64_t x_last_dim = x.size(x.dim() - 1); | ||
| 32 | + TORCH_CHECK(x_last_dim % 2 == 0, "x last dim size should be even", OPS_ERROR(ErrCode::PARAM)); | ||
| 27 | 33 | ||
| 28 | - // check x last dim | 34 | + at::Tensor grad_x = npu_preparation::apply_tensor_without_format(x.sizes(), x.options()); |
| 29 | - int64_t x_last_dim = x.size(x.dim() - 1); | ||
| 30 | - TORCH_CHECK(x_last_dim % 2 == 0, "x last dim size should be even", OPS_ERROR(ErrCode::PARAM)); | ||
| 31 | 35 | ||
| 32 | - at::Tensor grad_x = npu_preparation::apply_tensor_without_format(x.sizes(), x.options()); | 36 | + at::Tensor grad_weight; |
| 33 | 37 | ||
| 34 | - at::Tensor grad_weight; | 38 | + if (weight.has_value() && weight->defined()) { |
| 39 | + grad_weight = npu_preparation::apply_tensor_without_format(weight.value().sizes(), weight.value().options()); | ||
| 40 | + } else { | ||
| 41 | + grad_weight = at::empty({0}, x.options().dtype(at::kFloat)); | ||
| 42 | + } | ||
| 35 | 43 | ||
| 36 | - if (weight.has_value() && weight->defined()) { | 44 | + EXEC_NPU_CMD(aclnnSwigluGroupQuantGrad, grad_y, x, weight, y_origin, group_index, clamp_limit, grad_x, grad_weight); |
| 37 | - grad_weight = npu_preparation::apply_tensor_without_format(weight.value().sizes(), weight.value().options()); | ||
| 38 | - } else { | ||
| 39 | - grad_weight = at::empty({0}, x.options().dtype(at::kFloat)); | ||
| 40 | - } | ||
| 41 | 45 | ||
| 42 | - EXEC_NPU_CMD(aclnnSwigluGroupQuantGrad, grad_y, x, weight, y_origin, group_index, clamp_limit, grad_x, grad_weight); | 46 | + return std::make_tuple(grad_x, grad_weight); |
| 43 | - | ||
| 44 | - return std::make_tuple(grad_x, grad_weight); | ||
| 45 | } | 47 | } |
| 46 | } // namespace op_api | 48 | } // namespace op_api |
| @@ -23,56 +23,79 @@ using npu_preparation = at_npu::native::OpPreparation; | |||
| 23 | namespace { | 23 | namespace { |
| 24 | constexpr int64_t QUANT_MODE_2 = 2; | 24 | constexpr int64_t QUANT_MODE_2 = 2; |
| 25 | constexpr int64_t QUANT_MODE_3 = 3; | 25 | constexpr int64_t QUANT_MODE_3 = 3; |
| 26 | -} // namespace | 26 | +} // namespace |
| 27 | 27 | ||
| 28 | -std::tuple<at::Tensor, at::Tensor, at::Tensor> npu_swiglu_group_quant(const at::Tensor &x, | 28 | +std::tuple<at::Tensor, at::Tensor, at::Tensor> npu_swiglu_group_quant( |
| 29 | - const c10::optional<at::Tensor> &weight, const c10::optional<at::Tensor> &group_index, | 29 | + const at::Tensor& x, |
| 30 | - const c10::optional<at::Tensor> &scale, int64_t dst_type, int64_t quant_mode, | 30 | + const c10::optional<at::Tensor>& weight, |
| 31 | - int64_t block_size, bool round_scale, double clamp_limit, double dst_type_max, bool output_origin) | 31 | + const c10::optional<at::Tensor>& group_index, |
| 32 | -{ | 32 | + const c10::optional<at::Tensor>& scale, |
| 33 | - at::Tensor y; | 33 | + int64_t dst_type, |
| 34 | - at::Tensor y_scale; | 34 | + int64_t quant_mode, |
| 35 | - at::Tensor y_origin = at::empty({0}, x.options());; | 35 | + int64_t block_size, |
| 36 | + bool round_scale, | ||
| 37 | + double clamp_limit, | ||
| 38 | + double dst_type_max, | ||
| 39 | + bool output_origin) { | ||
| 40 | + at::Tensor y; | ||
| 41 | + at::Tensor y_scale; | ||
| 42 | + at::Tensor y_origin = at::empty({0}, x.options()); | ||
| 43 | + ; | ||
| 36 | 44 | ||
| 37 | - int64_t x_last_dim = x.size(x.dim() - 1); | 45 | + int64_t x_last_dim = x.size(x.dim() - 1); |
| 38 | - TORCH_CHECK(x_last_dim % 2 == 0, "x last dim size should be even", OPS_ERROR(ErrCode::PARAM)); | 46 | + TORCH_CHECK(x_last_dim % 2 == 0, "x last dim size should be even", OPS_ERROR(ErrCode::PARAM)); |
| 39 | 47 | ||
| 40 | - auto y_shape = op_infer::array_to_small_vector(x.sizes()); | 48 | + auto y_shape = op_infer::array_to_small_vector(x.sizes()); |
| 41 | - y_shape[x.dim() - 1] = x_last_dim / 2; | 49 | + y_shape[x.dim() - 1] = x_last_dim / 2; |
| 42 | 50 | ||
| 43 | - aclDataType y_acltype; | 51 | + aclDataType y_acltype; |
| 44 | - if (quant_mode == QUANT_MODE_2 || quant_mode == QUANT_MODE_3) { | 52 | + if (quant_mode == QUANT_MODE_2 || quant_mode == QUANT_MODE_3) { |
| 45 | - y_acltype = aclDataType::ACL_HIFLOAT8; | 53 | + y_acltype = aclDataType::ACL_HIFLOAT8; |
| 46 | - y = npu_preparation::apply_tensor_without_format(y_shape, at::ScalarType::Byte); | 54 | + y = npu_preparation::apply_tensor_without_format(y_shape, at::ScalarType::Byte); |
| 55 | + } | ||
| 56 | + | ||
| 57 | + if (quant_mode == QUANT_MODE_2) { | ||
| 58 | + y_scale = at::empty({0}, x.options().dtype(at::kFloat)); | ||
| 59 | + } else if (quant_mode == QUANT_MODE_3) { | ||
| 60 | + if (group_index.has_value() && group_index->defined()) { | ||
| 61 | + y_scale = | ||
| 62 | + npu_preparation::apply_tensor_without_format(group_index.value().sizes(), c10::dtype(at::ScalarType::Float)); | ||
| 63 | + } else { | ||
| 64 | + y_scale = npu_preparation::apply_tensor_without_format({1}, c10::dtype(at::ScalarType::Float)); | ||
| 47 | } | 65 | } |
| 66 | + } | ||
| 48 | 67 | ||
| 49 | - if (quant_mode == QUANT_MODE_2) { | 68 | + if (output_origin) { |
| 50 | - y_scale = at::empty({0}, x.options().dtype(at::kFloat)); | 69 | + auto y_origin_shape = op_infer::array_to_small_vector(x.sizes()); |
| 51 | - } else if (quant_mode == QUANT_MODE_3) { | 70 | + y_origin_shape[x.dim() - 1] = x_last_dim / 2; |
| 52 | - if (group_index.has_value() && group_index->defined()) { | 71 | + y_origin = npu_preparation::apply_tensor_without_format(y_origin_shape, x.options()); |
| 53 | - y_scale = npu_preparation::apply_tensor_without_format(group_index.value().sizes(), c10::dtype(at::ScalarType::Float)); | 72 | + } |
| 54 | - } else { | ||
| 55 | - y_scale = npu_preparation::apply_tensor_without_format({1}, c10::dtype(at::ScalarType::Float)); | ||
| 56 | - } | ||
| 57 | - } | ||
| 58 | 73 | ||
| 59 | - if (output_origin) { | 74 | + TensorWrapper y_wrapper = {y, y_acltype}; |
| 60 | - auto y_origin_shape = op_infer::array_to_small_vector(x.sizes()); | ||
| 61 | - y_origin_shape[x.dim() - 1] = x_last_dim / 2; | ||
| 62 | - y_origin = npu_preparation::apply_tensor_without_format(y_origin_shape, x.options()); | ||
| 63 | - } | ||
| 64 | 75 | ||
| 65 | - TensorWrapper y_wrapper = {y, y_acltype}; | 76 | + aclDataType y_scale_acltype = npu_preparation::convert_to_acl_data_type(y_scale.scalar_type()); |
| 66 | 77 | ||
| 67 | - aclDataType y_scale_acltype = npu_preparation::convert_to_acl_data_type(y_scale.scalar_type()); | 78 | + TensorWrapper y_scale_wrapper = {y_scale, y_scale_acltype}; |
| 68 | 79 | ||
| 69 | - TensorWrapper y_scale_wrapper = {y_scale, y_scale_acltype}; | 80 | + TensorWrapper y_origin_wrapper = {y_origin, npu_preparation::convert_to_acl_data_type(y_origin.scalar_type())}; |
| 70 | 81 | ||
| 71 | - TensorWrapper y_origin_wrapper = {y_origin, npu_preparation::convert_to_acl_data_type(y_origin.scalar_type())}; | 82 | + EXEC_NPU_CMD( |
| 83 | + aclnnSwigluGroupQuant, | ||
| 84 | + x, | ||
| 85 | + weight, | ||
| 86 | + group_index, | ||
| 87 | + scale, | ||
| 88 | + y_acltype, | ||
| 89 | + quant_mode, | ||
| 90 | + block_size, | ||
| 91 | + round_scale, | ||
| 92 | + clamp_limit, | ||
| 93 | + dst_type_max, | ||
| 94 | + output_origin, | ||
| 95 | + y_wrapper, | ||
| 96 | + y_scale_wrapper, | ||
| 97 | + y_origin_wrapper); | ||
| 72 | 98 | ||
| 73 | - EXEC_NPU_CMD(aclnnSwigluGroupQuant, x, weight, group_index, scale, y_acltype, quant_mode, | 99 | + return std::make_tuple(y, y_scale, y_origin); |
| 74 | - block_size, round_scale, clamp_limit, dst_type_max, output_origin, y_wrapper, y_scale_wrapper, y_origin_wrapper); | ||
| 75 | - | ||
| 76 | - return std::make_tuple(y, y_scale, y_origin); | ||
| 77 | } | 100 | } |
| 78 | -} // namespace op_api | 101 | +} // namespace op_api |
| @@ -21,111 +21,151 @@ const int64_t NUM_TWO = 2; | |||
| 21 | constexpr float DEFAULT_BLOCKSIZE = 64.0; | 21 | constexpr float DEFAULT_BLOCKSIZE = 64.0; |
| 22 | 22 | ||
| 23 | std::tuple<at::Tensor, at::Tensor> npu_swiglu_mx_quant( | 23 | std::tuple<at::Tensor, at::Tensor> npu_swiglu_mx_quant( |
| 24 | - const at::Tensor& x, const c10::optional<at::Tensor>& group_index, | 24 | + const at::Tensor& x, |
| 25 | - int64_t activate_dim, bool activate_left, int64_t swiglu_mode, | 25 | + const c10::optional<at::Tensor>& group_index, |
| 26 | - double clamp_limit, double glu_alpha, double glu_bias, | 26 | + int64_t activate_dim, |
| 27 | - int64_t group_mode, int64_t axis, int64_t dst_type, | 27 | + bool activate_left, |
| 28 | - c10::string_view round_mode, int64_t scale_alg, double max_dtype_value) | 28 | + int64_t swiglu_mode, |
| 29 | -{ | 29 | + double clamp_limit, |
| 30 | - TORCH_CHECK(x.dim() > 1, "x dim should larger than 1", OPS_ERROR(ErrCode::PARAM)); | 30 | + double glu_alpha, |
| 31 | - TORCH_CHECK(swiglu_mode == 0 || swiglu_mode == 1, "swiglu_mode only support 0 or 1, but got ", swiglu_mode, | 31 | + double glu_bias, |
| 32 | - OPS_ERROR(ErrCode::PARAM)); | 32 | + int64_t group_mode, |
| 33 | - TORCH_CHECK(std::isfinite(clamp_limit) && clamp_limit > 0.0, "clamp_limit should be positive finite", | 33 | + int64_t axis, |
| 34 | - OPS_ERROR(ErrCode::PARAM)); | 34 | + int64_t dst_type, |
| 35 | - TORCH_CHECK(std::isfinite(glu_alpha), "glu_alpha should be finite", OPS_ERROR(ErrCode::PARAM)); | 35 | + c10::string_view round_mode, |
| 36 | - TORCH_CHECK(std::isfinite(glu_bias), "glu_bias should be finite", OPS_ERROR(ErrCode::PARAM)); | 36 | + int64_t scale_alg, |
| 37 | + double max_dtype_value) { | ||
| 38 | + TORCH_CHECK(x.dim() > 1, "x dim should larger than 1", OPS_ERROR(ErrCode::PARAM)); | ||
| 39 | + TORCH_CHECK( | ||
| 40 | + swiglu_mode == 0 || swiglu_mode == 1, | ||
| 41 | + "swiglu_mode only support 0 or 1, but got ", | ||
| 42 | + swiglu_mode, | ||
| 43 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 44 | + TORCH_CHECK( | ||
| 45 | + std::isfinite(clamp_limit) && clamp_limit > 0.0, | ||
| 46 | + "clamp_limit should be positive finite", | ||
| 47 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 48 | + TORCH_CHECK(std::isfinite(glu_alpha), "glu_alpha should be finite", OPS_ERROR(ErrCode::PARAM)); | ||
| 49 | + TORCH_CHECK(std::isfinite(glu_bias), "glu_bias should be finite", OPS_ERROR(ErrCode::PARAM)); | ||
| 37 | 50 | ||
| 38 | - static const bool is_available = check_aclnn_kernel_available("aclnnSwigluMxQuant"); | 51 | + static const bool is_available = check_aclnn_kernel_available("aclnnSwigluMxQuant"); |
| 39 | - TORCH_CHECK(is_available, | 52 | + TORCH_CHECK( |
| 40 | - "Current CANN version do not support this api. Please try to update the version of CANN." | 53 | + is_available, |
| 41 | - + OPS_ERROR(ErrCode::PARAM)); | 54 | + "Current CANN version do not support this api. Please try to update the version of CANN." + |
| 55 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 42 | 56 | ||
| 43 | - const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); | 57 | + const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); |
| 44 | 58 | ||
| 45 | - int64_t activate_dim_value = activate_dim; | 59 | + int64_t activate_dim_value = activate_dim; |
| 46 | - char *round_mode_ptr = const_cast<char *>(round_mode.data()); | 60 | + char* round_mode_ptr = const_cast<char*>(round_mode.data()); |
| 47 | 61 | ||
| 48 | - // transform activate_dim | 62 | + // transform activate_dim |
| 49 | - if (activate_dim_value < 0) { | 63 | + if (activate_dim_value < 0) { |
| 50 | - activate_dim_value = activate_dim_value + x.dim(); | 64 | + activate_dim_value = activate_dim_value + x.dim(); |
| 51 | - } | 65 | + } |
| 52 | - TORCH_CHECK(activate_dim_value <= (x.dim() - 1) && activate_dim_value >= 0, "activate_dim should be in range [0, x.dim()-1]", OPS_ERROR(ErrCode::PARAM)); | 66 | + TORCH_CHECK( |
| 67 | + activate_dim_value <= (x.dim() - 1) && activate_dim_value >= 0, | ||
| 68 | + "activate_dim should be in range [0, x.dim()-1]", | ||
| 69 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 53 | 70 | ||
| 54 | - // Calculate quant_dim based on axis | 71 | + // Calculate quant_dim based on axis |
| 55 | - int64_t quant_dim_value = axis; | 72 | + int64_t quant_dim_value = axis; |
| 56 | - if (quant_dim_value < 0) { | 73 | + if (quant_dim_value < 0) { |
| 57 | - quant_dim_value = quant_dim_value + x.dim(); | 74 | + quant_dim_value = quant_dim_value + x.dim(); |
| 58 | - } | 75 | + } |
| 59 | 76 | ||
| 60 | - TORCH_CHECK(quant_dim_value >= 0 && quant_dim_value <= (x.dim() - 1), "quant_dim should be in range [0, x.dim()-1]", OPS_ERROR(ErrCode::PARAM)); | 77 | + TORCH_CHECK( |
| 78 | + quant_dim_value >= 0 && quant_dim_value <= (x.dim() - 1), | ||
| 79 | + "quant_dim should be in range [0, x.dim()-1]", | ||
| 80 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 61 | 81 | ||
| 62 | - // select_dim is used to determine which dimension to divide by 2 for y and scale shapes | 82 | + // select_dim is used to determine which dimension to divide by 2 for y and scale shapes |
| 63 | - int64_t select_dim = activate_dim_value; | 83 | + int64_t select_dim = activate_dim_value; |
| 64 | 84 | ||
| 65 | - at::SmallVector<int64_t, op_infer::SIZE> y_size; | 85 | + at::SmallVector<int64_t, op_infer::SIZE> y_size; |
| 66 | - at::SmallVector<int64_t, op_infer::SIZE> scale_size; | 86 | + at::SmallVector<int64_t, op_infer::SIZE> scale_size; |
| 67 | 87 | ||
| 68 | - // Infer size of y, scale (divide by 2 at select_dim) | 88 | + // Infer size of y, scale (divide by 2 at select_dim) |
| 69 | - for (int i = 0; i < x.dim(); i++) { | 89 | + for (int i = 0; i < x.dim(); i++) { |
| 70 | - if (i == select_dim) { | 90 | + if (i == select_dim) { |
| 71 | - y_size.push_back(x.size(i) / NUM_TWO); | 91 | + y_size.push_back(x.size(i) / NUM_TWO); |
| 72 | - scale_size.push_back(x.size(i) / NUM_TWO); | 92 | + scale_size.push_back(x.size(i) / NUM_TWO); |
| 73 | - } else { | ||
| 74 | - y_size.push_back(x.size(i)); | ||
| 75 | - scale_size.push_back(x.size(i)); | ||
| 76 | - } | ||
| 77 | - } | ||
| 78 | - | ||
| 79 | - // Calculate quant_size based on group_index and quant_dim (matching meta function logic) | ||
| 80 | - int64_t quant_size = 0; | ||
| 81 | - if (!group_index_opt.defined()) { | ||
| 82 | - // group_index is None: quant_size = ceil(scale_size[quant_dim] / 64) | ||
| 83 | - quant_size = static_cast<int64_t>(std::ceil(static_cast<double>(scale_size[quant_dim_value]) / DEFAULT_BLOCKSIZE)); | ||
| 84 | } else { | 93 | } else { |
| 85 | - // group_index exists | 94 | + y_size.push_back(x.size(i)); |
| 86 | - if (quant_dim_value == (x.dim() - 1)) { | 95 | + scale_size.push_back(x.size(i)); |
| 87 | - // quant_dim is last dimension: quant_size = ceil(scale_size[quant_dim] / 64) | ||
| 88 | - quant_size = static_cast<int64_t>(std::ceil(static_cast<double>(scale_size[quant_dim_value]) / DEFAULT_BLOCKSIZE)); | ||
| 89 | - } else { | ||
| 90 | - // quant_dim is not last dimension: quant_size = ceil(scale_size[quant_dim] / 64) + group_index.shape[0] | ||
| 91 | - quant_size = static_cast<int64_t>(std::floor(static_cast<double>(scale_size[quant_dim_value]) / DEFAULT_BLOCKSIZE)); | ||
| 92 | - quant_size = quant_size + group_index_opt.sizes()[0]; | ||
| 93 | - } | ||
| 94 | } | 96 | } |
| 97 | + } | ||
| 95 | 98 | ||
| 96 | - // Modify scale shape at quant_dim with quant_size, then append 2 | 99 | + // Calculate quant_size based on group_index and quant_dim (matching meta function logic) |
| 97 | - scale_size[quant_dim_value] = quant_size; | 100 | + int64_t quant_size = 0; |
| 98 | - scale_size.push_back(NUM_TWO); | 101 | + if (!group_index_opt.defined()) { |
| 99 | - | 102 | + // group_index is None: quant_size = ceil(scale_size[quant_dim] / 64) |
| 100 | - at::Tensor y; | 103 | + quant_size = static_cast<int64_t>(std::ceil(static_cast<double>(scale_size[quant_dim_value]) / DEFAULT_BLOCKSIZE)); |
| 101 | - aclDataType y_acltype; | 104 | + } else { |
| 102 | - | 105 | + // group_index exists |
| 103 | - if (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || | 106 | + if (quant_dim_value == (x.dim() - 1)) { |
| 104 | - dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)) { | 107 | + // quant_dim is last dimension: quant_size = ceil(scale_size[quant_dim] / 64) |
| 105 | - int64_t last_dim_val = y_size[x.dim() - 1]; | 108 | + quant_size = |
| 106 | - TORCH_CHECK(last_dim_val % NUM_TWO == 0, "Y last dim should be even when type of y is float4_e1m2 or float4_e2m1", OPS_ERROR(ErrCode::PARAM)); | 109 | + static_cast<int64_t>(std::ceil(static_cast<double>(scale_size[quant_dim_value]) / DEFAULT_BLOCKSIZE)); |
| 107 | - y_size[x.dim() - 1] = last_dim_val / NUM_TWO; | ||
| 108 | - } | ||
| 109 | - | ||
| 110 | - if (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || | ||
| 111 | - dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)) { | ||
| 112 | - y = npu_preparation::apply_tensor_without_format(y_size, c10::ScalarType::Byte); | ||
| 113 | - y_acltype = c10_npu::GetAclDataType(dst_type); | ||
| 114 | } else { | 110 | } else { |
| 115 | - y_acltype = c10_npu::GetAclDataType(dst_type); | 111 | + // quant_dim is not last dimension: quant_size = ceil(scale_size[quant_dim] / 64) + group_index.shape[0] |
| 116 | - at::ScalarType scalar_dtype = npu_preparation::convert_to_scalar_type(y_acltype); | 112 | + quant_size = |
| 117 | - y = npu_preparation::apply_tensor_without_format(y_size, c10::dtype(scalar_dtype)); | 113 | + static_cast<int64_t>(std::floor(static_cast<double>(scale_size[quant_dim_value]) / DEFAULT_BLOCKSIZE)); |
| 114 | + quant_size = quant_size + group_index_opt.sizes()[0]; | ||
| 118 | } | 115 | } |
| 116 | + } | ||
| 119 | 117 | ||
| 120 | - TensorWrapper y_wrapper = {y, y_acltype}; | 118 | + // Modify scale shape at quant_dim with quant_size, then append 2 |
| 119 | + scale_size[quant_dim_value] = quant_size; | ||
| 120 | + scale_size.push_back(NUM_TWO); | ||
| 121 | 121 | ||
| 122 | - at::Tensor scale = npu_preparation::apply_tensor_without_format(scale_size, c10::dtype(c10::ScalarType::Byte)); | 122 | + at::Tensor y; |
| 123 | - TensorWrapper mxscale_wrapper = {scale, aclDataType::ACL_FLOAT8_E8M0}; | 123 | + aclDataType y_acltype; |
| 124 | 124 | ||
| 125 | - EXEC_NPU_CMD(aclnnSwigluMxQuant, x, group_index_opt, activate_dim_value, activate_left, | 125 | + if (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || |
| 126 | - swiglu_mode, clamp_limit, glu_alpha, glu_bias, group_mode, axis, | 126 | + dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)) { |
| 127 | - y_acltype, round_mode_ptr, scale_alg, max_dtype_value, y_wrapper, mxscale_wrapper); | 127 | + int64_t last_dim_val = y_size[x.dim() - 1]; |
| 128 | + TORCH_CHECK( | ||
| 129 | + last_dim_val % NUM_TWO == 0, | ||
| 130 | + "Y last dim should be even when type of y is float4_e1m2 or float4_e2m1", | ||
| 131 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 132 | + y_size[x.dim() - 1] = last_dim_val / NUM_TWO; | ||
| 133 | + } | ||
| 128 | 134 | ||
| 129 | - return std::tie(y, scale); | 135 | + if (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || |
| 136 | + dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)) { | ||
| 137 | + y = npu_preparation::apply_tensor_without_format(y_size, c10::ScalarType::Byte); | ||
| 138 | + y_acltype = c10_npu::GetAclDataType(dst_type); | ||
| 139 | + } else { | ||
| 140 | + y_acltype = c10_npu::GetAclDataType(dst_type); | ||
| 141 | + at::ScalarType scalar_dtype = npu_preparation::convert_to_scalar_type(y_acltype); | ||
| 142 | + y = npu_preparation::apply_tensor_without_format(y_size, c10::dtype(scalar_dtype)); | ||
| 143 | + } | ||
| 144 | + | ||
| 145 | + TensorWrapper y_wrapper = {y, y_acltype}; | ||
| 146 | + | ||
| 147 | + at::Tensor scale = npu_preparation::apply_tensor_without_format(scale_size, c10::dtype(c10::ScalarType::Byte)); | ||
| 148 | + TensorWrapper mxscale_wrapper = {scale, aclDataType::ACL_FLOAT8_E8M0}; | ||
| 149 | + | ||
| 150 | + EXEC_NPU_CMD( | ||
| 151 | + aclnnSwigluMxQuant, | ||
| 152 | + x, | ||
| 153 | + group_index_opt, | ||
| 154 | + activate_dim_value, | ||
| 155 | + activate_left, | ||
| 156 | + swiglu_mode, | ||
| 157 | + clamp_limit, | ||
| 158 | + glu_alpha, | ||
| 159 | + glu_bias, | ||
| 160 | + group_mode, | ||
| 161 | + axis, | ||
| 162 | + y_acltype, | ||
| 163 | + round_mode_ptr, | ||
| 164 | + scale_alg, | ||
| 165 | + max_dtype_value, | ||
| 166 | + y_wrapper, | ||
| 167 | + mxscale_wrapper); | ||
| 168 | + | ||
| 169 | + return std::tie(y, scale); | ||
| 130 | } | 170 | } |
| 131 | -} // namespace op_api | 171 | +} // namespace op_api |
| @@ -32,81 +32,95 @@ std::tuple<at::Tensor, at::Tensor, at::Tensor, at::Tensor> npu_swiglu_mx_quant_w | |||
| 32 | c10::string_view round_mode, | 32 | c10::string_view round_mode, |
| 33 | int64_t scale_alg, | 33 | int64_t scale_alg, |
| 34 | int64_t dst_type, | 34 | int64_t dst_type, |
| 35 | - double dst_type_max) | 35 | + double dst_type_max) { |
| 36 | -{ | 36 | + at::Tensor y1; |
| 37 | - at::Tensor y1; | 37 | + at::Tensor mxscale1; |
| 38 | - at::Tensor mxscale1; | 38 | + at::Tensor y2; |
| 39 | - at::Tensor y2; | 39 | + at::Tensor mxscale2; |
| 40 | - at::Tensor mxscale2; | ||
| 41 | 40 | ||
| 42 | - TORCH_CHECK(x.dim() >= MIN_INPUT_DIM, "The input x should be at least 2D" + OPS_ERROR(ErrCode::PARAM)); | 41 | + TORCH_CHECK(x.dim() >= MIN_INPUT_DIM, "The input x should be at least 2D" + OPS_ERROR(ErrCode::PARAM)); |
| 43 | - TORCH_CHECK(x.size(-1) % NUM_TWO == 0, "The last dim of input must be divisible by 2" + OPS_ERROR(ErrCode::PARAM)); | 42 | + TORCH_CHECK(x.size(-1) % NUM_TWO == 0, "The last dim of input must be divisible by 2" + OPS_ERROR(ErrCode::PARAM)); |
| 44 | 43 | ||
| 45 | - static const bool is_available = check_aclnn_kernel_available("aclnnSwigluMxQuantWithDualAxis"); | 44 | + static const bool is_available = check_aclnn_kernel_available("aclnnSwigluMxQuantWithDualAxis"); |
| 46 | - TORCH_CHECK(is_available, | 45 | + TORCH_CHECK( |
| 47 | - "Current CANN version do not support this api: npu_swiglu_mx_quant_with_dual_axis. Please try to update the version of CANN." | 46 | + is_available, |
| 48 | - + OPS_ERROR(ErrCode::PARAM)); | 47 | + "Current CANN version do not support this api: npu_swiglu_mx_quant_with_dual_axis. Please try to update the version of CANN." + |
| 48 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 49 | 49 | ||
| 50 | - const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); | 50 | + const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); |
| 51 | 51 | ||
| 52 | - char *round_mode_ptr = const_cast<char *>(round_mode.data()); | 52 | + char* round_mode_ptr = const_cast<char*>(round_mode.data()); |
| 53 | 53 | ||
| 54 | - // Infer y shape: divide last dim by 2 | 54 | + // Infer y shape: divide last dim by 2 |
| 55 | - auto y_shape = op_infer::array_to_small_vector(x.sizes()); | 55 | + auto y_shape = op_infer::array_to_small_vector(x.sizes()); |
| 56 | - y_shape[y_shape.size() - 1] = y_shape[y_shape.size() - 1] / NUM_TWO; | 56 | + y_shape[y_shape.size() - 1] = y_shape[y_shape.size() - 1] / NUM_TWO; |
| 57 | 57 | ||
| 58 | - // Infer mxscale1 shape: ceil(last_dim / 64) + append 2 | 58 | + // Infer mxscale1 shape: ceil(last_dim / 64) + append 2 |
| 59 | - auto mxscale1_shape = op_infer::array_to_small_vector(y_shape); | 59 | + auto mxscale1_shape = op_infer::array_to_small_vector(y_shape); |
| 60 | - int64_t last_dim = mxscale1_shape[mxscale1_shape.size() - 1]; | 60 | + int64_t last_dim = mxscale1_shape[mxscale1_shape.size() - 1]; |
| 61 | - mxscale1_shape[mxscale1_shape.size() - 1] = static_cast<int64_t>(std::ceil(static_cast<double>(last_dim) / SPLIT_BLOCK_SIZE)); | 61 | + mxscale1_shape[mxscale1_shape.size() - 1] = |
| 62 | - mxscale1_shape.emplace_back(NUM_TWO); | 62 | + static_cast<int64_t>(std::ceil(static_cast<double>(last_dim) / SPLIT_BLOCK_SIZE)); |
| 63 | + mxscale1_shape.emplace_back(NUM_TWO); | ||
| 63 | 64 | ||
| 64 | - // Infer mxscale2 shape: floor(second_to_last_dim / 64) + group_num + append 2 | 65 | + // Infer mxscale2 shape: floor(second_to_last_dim / 64) + group_num + append 2 |
| 65 | - auto mxscale2_shape = op_infer::array_to_small_vector(y_shape); | 66 | + auto mxscale2_shape = op_infer::array_to_small_vector(y_shape); |
| 66 | - int64_t second_to_last_dim = mxscale2_shape[mxscale2_shape.size() - 2]; | 67 | + int64_t second_to_last_dim = mxscale2_shape[mxscale2_shape.size() - 2]; |
| 67 | - int64_t quant_size = static_cast<int64_t>(std::ceil(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)); | 68 | + int64_t quant_size = static_cast<int64_t>(std::ceil(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)); |
| 68 | - if (group_index_opt.defined()) { | 69 | + if (group_index_opt.defined()) { |
| 69 | - quant_size = static_cast<int64_t>(std::floor(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)); | 70 | + quant_size = static_cast<int64_t>(std::floor(static_cast<double>(second_to_last_dim) / SPLIT_BLOCK_SIZE)); |
| 70 | - quant_size = quant_size + group_index_opt.size(0); | 71 | + quant_size = quant_size + group_index_opt.size(0); |
| 71 | - } | 72 | + } |
| 72 | - mxscale2_shape[mxscale2_shape.size() - 2] = quant_size; | 73 | + mxscale2_shape[mxscale2_shape.size() - 2] = quant_size; |
| 73 | - mxscale2_shape.emplace_back(NUM_TWO); | 74 | + mxscale2_shape.emplace_back(NUM_TWO); |
| 74 | 75 | ||
| 75 | - aclDataType y_acltype; | 76 | + aclDataType y_acltype; |
| 76 | - bool special_output_type = (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || | 77 | + bool special_output_type = |
| 77 | - dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)); | 78 | + (dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E2M1) || |
| 79 | + dst_type == static_cast<int64_t>(c10_npu::DType::FLOAT4_E1M2)); | ||
| 78 | 80 | ||
| 79 | - ASCEND_LOGI("[npu_swiglu_mx_quant_with_dual_axis]: Getting aclTensor y1 and y2 dtype by Parameter(dst_type): %ld", dst_type); | 81 | + ASCEND_LOGI( |
| 82 | + "[npu_swiglu_mx_quant_with_dual_axis]: Getting aclTensor y1 and y2 dtype by Parameter(dst_type): %ld", dst_type); | ||
| 80 | 83 | ||
| 81 | - if (special_output_type) { | 84 | + if (special_output_type) { |
| 82 | - int64_t y_last_dim_val = y_shape[y_shape.size() - 1]; | 85 | + int64_t y_last_dim_val = y_shape[y_shape.size() - 1]; |
| 83 | - TORCH_CHECK(y_last_dim_val % NUM_TWO == 0, | 86 | + TORCH_CHECK( |
| 84 | - "The last dim of y must be divisible by 2 if y dtype is float4_e2m1 or float4_e1m2" | 87 | + y_last_dim_val % NUM_TWO == 0, |
| 85 | - + OPS_ERROR(ErrCode::PARAM)); | 88 | + "The last dim of y must be divisible by 2 if y dtype is float4_e2m1 or float4_e1m2" + |
| 86 | - y_shape[y_shape.size() - 1] = y_last_dim_val / NUM_TWO; | 89 | + OPS_ERROR(ErrCode::PARAM)); |
| 87 | - y1 = npu_preparation::apply_tensor_without_format(y_shape, c10::ScalarType::Byte); | 90 | + y_shape[y_shape.size() - 1] = y_last_dim_val / NUM_TWO; |
| 88 | - y2 = npu_preparation::apply_tensor_without_format(y_shape, c10::ScalarType::Byte); | 91 | + y1 = npu_preparation::apply_tensor_without_format(y_shape, c10::ScalarType::Byte); |
| 89 | - y_acltype = c10_npu::GetAclDataType(dst_type); | 92 | + y2 = npu_preparation::apply_tensor_without_format(y_shape, c10::ScalarType::Byte); |
| 90 | - } else { | 93 | + y_acltype = c10_npu::GetAclDataType(dst_type); |
| 91 | - y_acltype = c10_npu::GetAclDataType(dst_type); | 94 | + } else { |
| 92 | - at::ScalarType scalar_dtype = npu_preparation::convert_to_scalar_type(y_acltype); | 95 | + y_acltype = c10_npu::GetAclDataType(dst_type); |
| 93 | - y1 = npu_preparation::apply_tensor_without_format(y_shape, c10::dtype(scalar_dtype)); | 96 | + at::ScalarType scalar_dtype = npu_preparation::convert_to_scalar_type(y_acltype); |
| 94 | - y2 = npu_preparation::apply_tensor_without_format(y_shape, c10::dtype(scalar_dtype)); | 97 | + y1 = npu_preparation::apply_tensor_without_format(y_shape, c10::dtype(scalar_dtype)); |
| 95 | - } | 98 | + y2 = npu_preparation::apply_tensor_without_format(y_shape, c10::dtype(scalar_dtype)); |
| 99 | + } | ||
| 96 | 100 | ||
| 97 | - mxscale1 = npu_preparation::apply_tensor_without_format(mxscale1_shape, c10::dtype(at::ScalarType::Byte)); | 101 | + mxscale1 = npu_preparation::apply_tensor_without_format(mxscale1_shape, c10::dtype(at::ScalarType::Byte)); |
| 98 | - mxscale2 = npu_preparation::apply_tensor_without_format(mxscale2_shape, c10::dtype(at::ScalarType::Byte)); | 102 | + mxscale2 = npu_preparation::apply_tensor_without_format(mxscale2_shape, c10::dtype(at::ScalarType::Byte)); |
| 99 | 103 | ||
| 100 | - TensorWrapper y1_wrapper = {y1, y_acltype}; | 104 | + TensorWrapper y1_wrapper = {y1, y_acltype}; |
| 101 | - TensorWrapper y2_wrapper = {y2, y_acltype}; | 105 | + TensorWrapper y2_wrapper = {y2, y_acltype}; |
| 102 | - TensorWrapper mxscale1_wrapper = {mxscale1, aclDataType::ACL_FLOAT8_E8M0}; | 106 | + TensorWrapper mxscale1_wrapper = {mxscale1, aclDataType::ACL_FLOAT8_E8M0}; |
| 103 | - TensorWrapper mxscale2_wrapper = {mxscale2, aclDataType::ACL_FLOAT8_E8M0}; | 107 | + TensorWrapper mxscale2_wrapper = {mxscale2, aclDataType::ACL_FLOAT8_E8M0}; |
| 104 | 108 | ||
| 105 | - EXEC_NPU_CMD(aclnnSwigluMxQuantWithDualAxis, x, group_index_opt, activate_left, | 109 | + EXEC_NPU_CMD( |
| 106 | - round_mode_ptr, scale_alg, y_acltype, dst_type_max, | 110 | + aclnnSwigluMxQuantWithDualAxis, |
| 107 | - y1_wrapper, mxscale1_wrapper, y2_wrapper, mxscale2_wrapper); | 111 | + x, |
| 112 | + group_index_opt, | ||
| 113 | + activate_left, | ||
| 114 | + round_mode_ptr, | ||
| 115 | + scale_alg, | ||
| 116 | + y_acltype, | ||
| 117 | + dst_type_max, | ||
| 118 | + y1_wrapper, | ||
| 119 | + mxscale1_wrapper, | ||
| 120 | + y2_wrapper, | ||
| 121 | + mxscale2_wrapper); | ||
| 108 | 122 | ||
| 109 | - return std::make_tuple(y1, mxscale1, y2, mxscale2); | 123 | + return std::make_tuple(y1, mxscale1, y2, mxscale2); |
| 110 | } | 124 | } |
| 111 | 125 | ||
| 112 | } // namespace op_api | 126 | } // namespace op_api |
| @@ -26,61 +26,90 @@ constexpr int64_t MAX_LAST_DIM = 8192; | |||
| 26 | // the last dimension of x should be divisible by 4 | 26 | // the last dimension of x should be divisible by 4 |
| 27 | constexpr int64_t DIV_LAST_DIM = 4; | 27 | constexpr int64_t DIV_LAST_DIM = 4; |
| 28 | constexpr int64_t INT4_IN_INT8_NUM = 2; | 28 | constexpr int64_t INT4_IN_INT8_NUM = 2; |
| 29 | -} // namespace | 29 | +} // namespace |
| 30 | 30 | ||
| 31 | -std::tuple<at::Tensor, at::Tensor> npu_swiglu_quant(const at::Tensor& x, const c10::optional<at::Tensor>& smooth_scales, | 31 | +std::tuple<at::Tensor, at::Tensor> npu_swiglu_quant( |
| 32 | - const c10::optional<at::Tensor>& offsets, const c10::optional<at::Tensor>& group_index, bool activate_left, | 32 | + const at::Tensor& x, |
| 33 | - int64_t quant_mode, int64_t group_list_type, c10::optional<at::ScalarType> dst_type) | 33 | + const c10::optional<at::Tensor>& smooth_scales, |
| 34 | -{ | 34 | + const c10::optional<at::Tensor>& offsets, |
| 35 | - TORCH_CHECK(quant_mode == 0 || quant_mode == 1, "quant_mode only support 0(static) or 1(dynamic), but got ", | 35 | + const c10::optional<at::Tensor>& group_index, |
| 36 | - quant_mode, OPS_ERROR(ErrCode::PARAM)); | 36 | + bool activate_left, |
| 37 | - TORCH_CHECK(group_list_type == 0 || group_list_type == 1, | 37 | + int64_t quant_mode, |
| 38 | - "group_list_type only support 0(cumsum) or 1(count), but got ", | 38 | + int64_t group_list_type, |
| 39 | - group_list_type, OPS_ERROR(ErrCode::PARAM)); | 39 | + c10::optional<at::ScalarType> dst_type) { |
| 40 | - TORCH_CHECK(!dst_type.has_value() || dst_type == at::ScalarType::Char || dst_type == at::ScalarType::QUInt4x2, | 40 | + TORCH_CHECK( |
| 41 | - "dtype must be torch.int8 for int8 or torch.quint4x2 for int4" + OPS_ERROR(ErrCode::TYPE)); | 41 | + quant_mode == 0 || quant_mode == 1, |
| 42 | - if (!dst_type.has_value()) { | 42 | + "quant_mode only support 0(static) or 1(dynamic), but got ", |
| 43 | - // dst_type default is torch.int8 | 43 | + quant_mode, |
| 44 | - dst_type = at::ScalarType::Char; | 44 | + OPS_ERROR(ErrCode::PARAM)); |
| 45 | - } | 45 | + TORCH_CHECK( |
| 46 | + group_list_type == 0 || group_list_type == 1, | ||
| 47 | + "group_list_type only support 0(cumsum) or 1(count), but got ", | ||
| 48 | + group_list_type, | ||
| 49 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 50 | + TORCH_CHECK( | ||
| 51 | + !dst_type.has_value() || dst_type == at::ScalarType::Char || dst_type == at::ScalarType::QUInt4x2, | ||
| 52 | + "dtype must be torch.int8 for int8 or torch.quint4x2 for int4" + OPS_ERROR(ErrCode::TYPE)); | ||
| 53 | + if (!dst_type.has_value()) { | ||
| 54 | + // dst_type default is torch.int8 | ||
| 55 | + dst_type = at::ScalarType::Char; | ||
| 56 | + } | ||
| 46 | 57 | ||
| 47 | - const at::Tensor& smooth_scales_opt = c10::value_or_else(smooth_scales, [] { return at::Tensor(); }); | 58 | + const at::Tensor& smooth_scales_opt = c10::value_or_else(smooth_scales, [] { return at::Tensor(); }); |
| 48 | - const at::Tensor& offsets_opt = c10::value_or_else(offsets, [] { return at::Tensor(); }); | 59 | + const at::Tensor& offsets_opt = c10::value_or_else(offsets, [] { return at::Tensor(); }); |
| 49 | - TORCH_CHECK(quant_mode != 0 || smooth_scales_opt.sizes() == offsets_opt.sizes(), | 60 | + TORCH_CHECK( |
| 50 | - "smooth_scales and offsets should have the same shape when quant_mode is 0", | 61 | + quant_mode != 0 || smooth_scales_opt.sizes() == offsets_opt.sizes(), |
| 51 | - OPS_ERROR(ErrCode::PARAM)); | 62 | + "smooth_scales and offsets should have the same shape when quant_mode is 0", |
| 52 | - | 63 | + OPS_ERROR(ErrCode::PARAM)); |
| 53 | - // check x last dim | ||
| 54 | - int64_t x_last_dim = x.size(x.dim() - 1); | ||
| 55 | - TORCH_CHECK(x_last_dim <= MAX_LAST_DIM, "x last dim size should not be larger than ", MAX_LAST_DIM, ", but got ", | ||
| 56 | - x_last_dim, OPS_ERROR(ErrCode::PARAM)); | ||
| 57 | - TORCH_CHECK(x_last_dim % 2 == 0, "x last dim size should be even", OPS_ERROR(ErrCode::PARAM)); | ||
| 58 | - // to concatenate two INT4 into one INT8, the last dimension of x should be divisible by 4 | ||
| 59 | - TORCH_CHECK(dst_type != at::ScalarType::QUInt4x2 || x_last_dim % DIV_LAST_DIM == 0, | ||
| 60 | - "x shape last dim must be divded by 4 when dst_type is torch.quint4x2, but got ", | ||
| 61 | - x_last_dim, OPS_ERROR(ErrCode::PARAM)); | ||
| 62 | 64 | ||
| 63 | - at::SmallVector<int64_t, op_infer::SIZE> y_size; | 65 | + // check x last dim |
| 64 | - at::SmallVector<int64_t, op_infer::SIZE> scale_size; | 66 | + int64_t x_last_dim = x.size(x.dim() - 1); |
| 65 | - for (int i = 0; i < x.dim() - 1; i++) { | 67 | + TORCH_CHECK( |
| 66 | - y_size.push_back(x.size(i)); | 68 | + x_last_dim <= MAX_LAST_DIM, |
| 67 | - scale_size.push_back(x.size(i)); | 69 | + "x last dim size should not be larger than ", |
| 68 | - } | 70 | + MAX_LAST_DIM, |
| 69 | - auto last_dim = dst_type == at::ScalarType::Char ? x_last_dim / 2 : x_last_dim / 2 / INT4_IN_INT8_NUM; | 71 | + ", but got ", |
| 70 | - y_size.push_back(last_dim); | 72 | + x_last_dim, |
| 73 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 74 | + TORCH_CHECK(x_last_dim % 2 == 0, "x last dim size should be even", OPS_ERROR(ErrCode::PARAM)); | ||
| 75 | + // to concatenate two INT4 into one INT8, the last dimension of x should be divisible by 4 | ||
| 76 | + TORCH_CHECK( | ||
| 77 | + dst_type != at::ScalarType::QUInt4x2 || x_last_dim % DIV_LAST_DIM == 0, | ||
| 78 | + "x shape last dim must be divded by 4 when dst_type is torch.quint4x2, but got ", | ||
| 79 | + x_last_dim, | ||
| 80 | + OPS_ERROR(ErrCode::PARAM)); | ||
| 71 | 81 | ||
| 72 | - // The dtype of y is INT8(char), change y_size for different quantization types | 82 | + at::SmallVector<int64_t, op_infer::SIZE> y_size; |
| 73 | - at::Tensor y = npu_preparation::apply_tensor_without_format(y_size, c10::dtype(c10::ScalarType::Char)); | 83 | + at::SmallVector<int64_t, op_infer::SIZE> scale_size; |
| 74 | - at::Tensor scale = npu_preparation::apply_tensor_without_format(scale_size, c10::dtype(c10::ScalarType::Float)); | 84 | + for (int i = 0; i < x.dim() - 1; i++) { |
| 85 | + y_size.push_back(x.size(i)); | ||
| 86 | + scale_size.push_back(x.size(i)); | ||
| 87 | + } | ||
| 88 | + auto last_dim = dst_type == at::ScalarType::Char ? x_last_dim / 2 : x_last_dim / 2 / INT4_IN_INT8_NUM; | ||
| 89 | + y_size.push_back(last_dim); | ||
| 75 | 90 | ||
| 76 | - std::string quant_mode_str = quant_mode == 0 ? "static" : "dynamic"; | 91 | + // The dtype of y is INT8(char), change y_size for different quantization types |
| 77 | - char* quant_mode_ptr = const_cast<char*>(quant_mode_str.c_str()); | 92 | + at::Tensor y = npu_preparation::apply_tensor_without_format(y_size, c10::dtype(c10::ScalarType::Char)); |
| 93 | + at::Tensor scale = npu_preparation::apply_tensor_without_format(scale_size, c10::dtype(c10::ScalarType::Float)); | ||
| 78 | 94 | ||
| 79 | - const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); | 95 | + std::string quant_mode_str = quant_mode == 0 ? "static" : "dynamic"; |
| 80 | - int output_type = dst_type == at::ScalarType::Char ? INT8 : INT4; | 96 | + char* quant_mode_ptr = const_cast<char*>(quant_mode_str.c_str()); |
| 81 | - EXEC_NPU_CMD(aclnnSwiGluQuantV2, x, smooth_scales_opt, offsets_opt, group_index_opt, activate_left, quant_mode_ptr, | ||
| 82 | - group_list_type, output_type, y, scale); | ||
| 83 | 97 | ||
| 84 | - return std::tie(y, scale); | 98 | + const at::Tensor& group_index_opt = c10::value_or_else(group_index, [] { return at::Tensor(); }); |
| 99 | + int output_type = dst_type == at::ScalarType::Char ? INT8 : INT4; | ||
| 100 | + EXEC_NPU_CMD( | ||
| 101 | + aclnnSwiGluQuantV2, | ||
| 102 | + x, | ||
| 103 | + smooth_scales_opt, | ||
| 104 | + offsets_opt, | ||
| 105 | + group_index_opt, | ||
| 106 | + activate_left, | ||
| 107 | + quant_mode_ptr, | ||
| 108 | + group_list_type, | ||
| 109 | + output_type, | ||
| 110 | + y, | ||
| 111 | + scale); | ||
| 112 | + | ||
| 113 | + return std::tie(y, scale); | ||
| 85 | } | 114 | } |
| 86 | -} // namespace op_api | 115 | +} // namespace op_api |
| @@ -20,28 +20,29 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -at::Tensor& tanh_out(const at::Tensor& self, at::Tensor& result) | 23 | +at::Tensor& tanh_out(const at::Tensor& self, at::Tensor& result) { |
| 24 | -{ | 24 | + DO_COMPATIBILITY(aclnnTanh, acl_op::tanh_out(self, result)); |
| 25 | - DO_COMPATIBILITY(aclnnTanh, acl_op::tanh_out(self, result)); | 25 | + TORCH_CHECK( |
| 26 | - TORCH_CHECK(!isIntegralType(result.scalar_type(), true), "result dtype can't be cast to the desired output type.\n", | 26 | + !isIntegralType(result.scalar_type(), true), |
| 27 | - OPS_ERROR(ErrCode::TYPE)); | 27 | + "result dtype can't be cast to the desired output type.\n", |
| 28 | - npu_preparation::check_tensor({self}, result, result, self.sizes()); | 28 | + OPS_ERROR(ErrCode::TYPE)); |
| 29 | - at_npu::native::OpPreparation::check_memory({self}, {result}); | 29 | + npu_preparation::check_tensor({self}, result, result, self.sizes()); |
| 30 | - EXEC_NPU_CMD(aclnnTanh, self, result); | 30 | + at_npu::native::OpPreparation::check_memory({self}, {result}); |
| 31 | - at::namedinference::propagate_names(result, self); | 31 | + EXEC_NPU_CMD(aclnnTanh, self, result); |
| 32 | - return result; | 32 | + at::namedinference::propagate_names(result, self); |
| 33 | + return result; | ||
| 33 | } | 34 | } |
| 34 | 35 | ||
| 35 | at::Tensor tanh(const at::Tensor& self) { | 36 | at::Tensor tanh(const at::Tensor& self) { |
| 36 | - DO_COMPATIBILITY(aclnnTanh, acl_op::tanh(self)); | 37 | + DO_COMPATIBILITY(aclnnTanh, acl_op::tanh(self)); |
| 37 | - auto output_dtype = self.dtype(); | 38 | + auto output_dtype = self.dtype(); |
| 38 | - if (isIntegralType(self.scalar_type(), true)) { | 39 | + if (isIntegralType(self.scalar_type(), true)) { |
| 39 | - output_dtype = at::kFloat; | 40 | + output_dtype = at::kFloat; |
| 40 | - } | 41 | + } |
| 41 | - at::Tensor result = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(output_dtype)); | 42 | + at::Tensor result = npu_preparation::apply_tensor_without_format(self.sizes(), self.options().dtype(output_dtype)); |
| 42 | - EXEC_NPU_CMD(aclnnTanh, self, result); | 43 | + EXEC_NPU_CMD(aclnnTanh, self, result); |
| 43 | - at::namedinference::propagate_names(result, self); | 44 | + at::namedinference::propagate_names(result, self); |
| 44 | - return result; | 45 | + return result; |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | at::Tensor& tanh_(at::Tensor& self) { | 48 | at::Tensor& tanh_(at::Tensor& self) { |
| @@ -49,4 +50,4 @@ at::Tensor& tanh_(at::Tensor& self) { | |||
| 49 | EXEC_NPU_CMD(aclnnInplaceTanh, self); | 50 | EXEC_NPU_CMD(aclnnInplaceTanh, self); |
| 50 | return self; | 51 | return self; |
| 51 | } | 52 | } |
| 52 | -} | 53 | +} // namespace op_api |
| @@ -30,67 +30,49 @@ namespace sparse { | |||
| 30 | 30 | ||
| 31 | using namespace at::sparse; | 31 | using namespace at::sparse; |
| 32 | 32 | ||
| 33 | -SparseTensor _coalesce_sparse(const SparseTensor& self) | 33 | +SparseTensor _coalesce_sparse(const SparseTensor& self) { |
| 34 | -{ | 34 | + int64_t nnz = self._nnz(); |
| 35 | - int64_t nnz = self._nnz(); | 35 | + TORCH_CHECK(!self.is_coalesced(), OPS_ERROR(ErrCode::VALUE)); |
| 36 | - TORCH_CHECK(!self.is_coalesced(), OPS_ERROR(ErrCode::VALUE)); | 36 | + if (nnz < 2) { |
| 37 | - if (nnz < 2) { | 37 | + SparseTensor dst = self.clone(); |
| 38 | - SparseTensor dst = self.clone(); | 38 | + dst._coalesced_(true); |
| 39 | - dst._coalesced_(true); | 39 | + return dst; |
| 40 | - return dst; | 40 | + } |
| 41 | - } | ||
| 42 | 41 | ||
| 43 | - at::Tensor values = self._values(); | 42 | + at::Tensor values = self._values(); |
| 44 | - at::Tensor indices = self._indices(); | 43 | + at::Tensor indices = self._indices(); |
| 45 | - at::Tensor indices_1d = at::sparse::flatten_indices(indices, self.sizes(), true); | 44 | + at::Tensor indices_1d = at::sparse::flatten_indices(indices, self.sizes(), true); |
| 46 | - auto unique_indices_info = at::_unique2(indices_1d, true, true); | 45 | + auto unique_indices_info = at::_unique2(indices_1d, true, true); |
| 47 | - at::Tensor unique_len = std::get<0>(unique_indices_info).to(at::kInt); | 46 | + at::Tensor unique_len = std::get<0>(unique_indices_info).to(at::kInt); |
| 48 | - auto new_nnz = unique_len.sizes()[0]; | 47 | + auto new_nnz = unique_len.sizes()[0]; |
| 49 | - auto new_values_size = values.sizes().vec(); | 48 | + auto new_values_size = values.sizes().vec(); |
| 50 | - new_values_size[0] = new_nnz; | 49 | + new_values_size[0] = new_nnz; |
| 51 | - at::Tensor new_indices_t = at::zeros( | 50 | + at::Tensor new_indices_t = at::zeros({new_nnz, indices.sizes()[0]}, indices.options().dtype(at::kInt)); |
| 52 | - {new_nnz, indices.sizes()[0]}, | 51 | + at::Tensor indices_t = at_npu::native::NpuUtils::format_contiguous(indices.transpose(0, 1)).to(at::kInt); |
| 53 | - indices.options().dtype(at::kInt)); | 52 | + at::Tensor unique_indices = std::get<1>(unique_indices_info).to(at::kInt); |
| 54 | - at::Tensor indices_t = at_npu::native::NpuUtils::format_contiguous(indices.transpose(0, 1)).to(at::kInt); | 53 | + if (values.scalar_type() == at::kHalf || (values.scalar_type() == at::kBFloat16)) { |
| 55 | - at::Tensor unique_indices = std::get<1>(unique_indices_info).to(at::kInt); | 54 | + at::Tensor values_f = values.to(at::kFloat); |
| 56 | - if (values.scalar_type() == at::kHalf || (values.scalar_type() == at::kBFloat16)) { | 55 | + at::Tensor new_values_f = at::zeros(new_values_size, values.options()).to(at::kFloat); |
| 57 | - at::Tensor values_f = values.to(at::kFloat); | 56 | + EXEC_NPU_CMD(aclnnCoalesceSparse, unique_len, unique_indices, indices_t, values_f, new_indices_t, new_values_f); |
| 58 | - at::Tensor new_values_f = at::zeros(new_values_size, values.options()).to(at::kFloat); | 57 | + at::Tensor new_indices = new_indices_t.transpose(0, 1).to(at::kLong); |
| 59 | - EXEC_NPU_CMD( | 58 | + if (values.scalar_type() == at::kHalf) { |
| 60 | - aclnnCoalesceSparse, | 59 | + at::Tensor new_values = new_values_f.to(at::kHalf); |
| 61 | - unique_len, | 60 | + SparseTensor dst = |
| 62 | - unique_indices, | 61 | + ::at::native::_sparse_coo_tensor_unsafe(new_indices, new_values, self.sizes())._coalesced_(true); |
| 63 | - indices_t, | 62 | + return dst; |
| 64 | - values_f, | ||
| 65 | - new_indices_t, | ||
| 66 | - new_values_f); | ||
| 67 | - at::Tensor new_indices = new_indices_t.transpose(0, 1).to(at::kLong); | ||
| 68 | - if (values.scalar_type() == at::kHalf) { | ||
| 69 | - at::Tensor new_values = new_values_f.to(at::kHalf); | ||
| 70 | - SparseTensor dst = ::at::native::_sparse_coo_tensor_unsafe(new_indices, | ||
| 71 | - new_values, self.sizes())._coalesced_(true); | ||
| 72 | - return dst; | ||
| 73 | - } else { | ||
| 74 | - at::Tensor new_values = new_values_f.to(at::kBFloat16); | ||
| 75 | - SparseTensor dst = ::at::native::_sparse_coo_tensor_unsafe(new_indices, | ||
| 76 | - new_values, self.sizes())._coalesced_(true); | ||
| 77 | - return dst; | ||
| 78 | - } | ||
| 79 | } else { | 63 | } else { |
| 80 | - at::Tensor new_values = at::zeros(new_values_size, values.options()); | 64 | + at::Tensor new_values = new_values_f.to(at::kBFloat16); |
| 81 | - EXEC_NPU_CMD( | 65 | + SparseTensor dst = |
| 82 | - aclnnCoalesceSparse, | 66 | + ::at::native::_sparse_coo_tensor_unsafe(new_indices, new_values, self.sizes())._coalesced_(true); |
| 83 | - unique_len, | 67 | + return dst; |
| 84 | - unique_indices, | ||
| 85 | - indices_t, | ||
| 86 | - values, | ||
| 87 | - new_indices_t, | ||
| 88 | - new_values); | ||
| 89 | - at::Tensor new_indices = new_indices_t.transpose(0, 1).to(at::kLong); | ||
| 90 | - SparseTensor dst = ::at::native::_sparse_coo_tensor_unsafe(new_indices, | ||
| 91 | - new_values, self.sizes())._coalesced_(true); | ||
| 92 | - return dst; | ||
| 93 | } | 68 | } |
| 69 | + } else { | ||
| 70 | + at::Tensor new_values = at::zeros(new_values_size, values.options()); | ||
| 71 | + EXEC_NPU_CMD(aclnnCoalesceSparse, unique_len, unique_indices, indices_t, values, new_indices_t, new_values); | ||
| 72 | + at::Tensor new_indices = new_indices_t.transpose(0, 1).to(at::kLong); | ||
| 73 | + SparseTensor dst = ::at::native::_sparse_coo_tensor_unsafe(new_indices, new_values, self.sizes())._coalesced_(true); | ||
| 74 | + return dst; | ||
| 75 | + } | ||
| 94 | } | 76 | } |
| 95 | 77 | ||
| 96 | -} // namespace at::native | 78 | +} // namespace sparse |
| @@ -18,16 +18,14 @@ | |||
| 18 | 18 | ||
| 19 | namespace sparse { | 19 | namespace sparse { |
| 20 | 20 | ||
| 21 | -at::Tensor max_sparse(const at::Tensor &self) | 21 | +at::Tensor max_sparse(const at::Tensor& self) { |
| 22 | -{ | 22 | + auto dense_tensor = self.to_dense(); |
| 23 | - auto dense_tensor = self.to_dense(); | 23 | + return at::max(dense_tensor); |
| 24 | - return at::max(dense_tensor); | ||
| 25 | } | 24 | } |
| 26 | 25 | ||
| 27 | -at::Tensor &max_out_sparse(const at::Tensor &self, const at::Tensor &other, at::Tensor &result) | 26 | +at::Tensor& max_out_sparse(const at::Tensor& self, const at::Tensor& other, at::Tensor& result) { |
| 28 | -{ | 27 | + auto dense_tensor = self.to_dense(); |
| 29 | - auto dense_tensor = self.to_dense(); | 28 | + return at::max_out(dense_tensor, other, result); |
| 30 | - return at::max_out(dense_tensor, other, result); | ||
| 31 | } | 29 | } |
| 32 | 30 | ||
| 33 | } // namespace sparse | 31 | } // namespace sparse |
| @@ -22,21 +22,16 @@ | |||
| 22 | namespace sparse { | 22 | namespace sparse { |
| 23 | using namespace at::sparse; | 23 | using namespace at::sparse; |
| 24 | 24 | ||
| 25 | -inline at::SparseTensorImpl* get_sparse_impl(const SparseTensor& self) | 25 | +inline at::SparseTensorImpl* get_sparse_impl(const SparseTensor& self) { |
| 26 | -{ | 26 | + TORCH_CHECK(self.is_sparse(), "_internal_get_SparseTensorImpl: not a sparse tensor", OPS_ERROR(ErrCode::VALUE)); |
| 27 | - TORCH_CHECK(self.is_sparse(), "_internal_get_SparseTensorImpl: not a sparse tensor", OPS_ERROR(ErrCode::VALUE)); | 27 | + return static_cast<at::SparseTensorImpl*>(self.unsafeGetTensorImpl()); |
| 28 | - return static_cast<at::SparseTensorImpl*>(self.unsafeGetTensorImpl()); | ||
| 29 | } | 28 | } |
| 30 | 29 | ||
| 31 | -inline void alias_into_sparse( | 30 | +inline void alias_into_sparse(const SparseTensor& self, const at::Tensor& indices, const at::Tensor& values) { |
| 32 | - const SparseTensor& self, | 31 | + get_sparse_impl(self)->set_indices_and_values_unsafe(indices, values); |
| 33 | - const at::Tensor& indices, | ||
| 34 | - const at::Tensor& values) | ||
| 35 | -{ | ||
| 36 | - get_sparse_impl(self)->set_indices_and_values_unsafe(indices, values); | ||
| 37 | } | 32 | } |
| 38 | 33 | ||
| 39 | SparseTensor& mul_out_sparse_scalar(SparseTensor& r, const SparseTensor& t, const at::Scalar& value); | 34 | SparseTensor& mul_out_sparse_scalar(SparseTensor& r, const SparseTensor& t, const at::Scalar& value); |
| 40 | at::Tensor& mul_out_sparse(const at::Tensor& self, const at::Tensor& other, at::Tensor& out); | 35 | at::Tensor& mul_out_sparse(const at::Tensor& self, const at::Tensor& other, at::Tensor& out); |
| 41 | 36 | ||
| 42 | -} | 37 | +} // namespace sparse |
| @@ -43,506 +43,481 @@ struct MaxSizeExceeded : public std::exception {}; | |||
| 43 | //! | 43 | //! |
| 44 | //! 封装动态数组的顺序容器 | 44 | //! 封装动态数组的顺序容器 |
| 45 | //! | 45 | //! |
| 46 | -template <class T> class SVector { | 46 | +template <class T> |
| 47 | -public: | 47 | +class SVector { |
| 48 | - //! \brief 默认构造函数 | 48 | + public: |
| 49 | - //! | 49 | + //! \brief 默认构造函数 |
| 50 | - //! \note 容量为DEFAULT_SVECTOR_SIZE | 50 | + //! |
| 51 | - //! | 51 | + //! \note 容量为DEFAULT_SVECTOR_SIZE |
| 52 | - constexpr SVector() : size_(0) | 52 | + //! |
| 53 | - { | 53 | + constexpr SVector() : size_(0) { |
| 54 | - for (std::size_t i = 0; i < DEFAULT_SVECTOR_SIZE; ++i) { | 54 | + for (std::size_t i = 0; i < DEFAULT_SVECTOR_SIZE; ++i) { |
| 55 | - storage_[i] = {}; | 55 | + storage_[i] = {}; |
| 56 | - } | ||
| 57 | } | 56 | } |
| 58 | - //! \brief 初始化列表构造函数 | 57 | + } |
| 59 | - //! | 58 | + //! \brief 初始化列表构造函数 |
| 60 | - //! \param list | 59 | + //! |
| 61 | - //! | 60 | + //! \param list |
| 62 | - //! \note list长度需小于DEFAULT_SVECTOR_SIZE,否则会抛出异常 | 61 | + //! |
| 63 | - //! | 62 | + //! \note list长度需小于DEFAULT_SVECTOR_SIZE,否则会抛出异常 |
| 64 | - SVector(std::initializer_list<T> list) | 63 | + //! |
| 65 | - { | 64 | + SVector(std::initializer_list<T> list) { |
| 66 | - if (CHECK_BOUND && list.size() > DEFAULT_SVECTOR_SIZE) { | 65 | + if (CHECK_BOUND && list.size() > DEFAULT_SVECTOR_SIZE) { |
| 67 | - throw MaxSizeExceeded(); | 66 | + throw MaxSizeExceeded(); |
| 68 | - } | ||
| 69 | - size_ = list.size(); | ||
| 70 | - size_t i = 0; | ||
| 71 | - for (auto it = list.begin(); it != list.end() && i < size_; ++it) { | ||
| 72 | - storage_[i++] = *it; | ||
| 73 | - } | ||
| 74 | } | 67 | } |
| 75 | - //! \brief 带参数的构造函数 | 68 | + size_ = list.size(); |
| 76 | - //! | 69 | + size_t i = 0; |
| 77 | - //! \param size | 70 | + for (auto it = list.begin(); it != list.end() && i < size_; ++it) { |
| 78 | - //! \param value | 71 | + storage_[i++] = *it; |
| 79 | - //! | ||
| 80 | - //! \note size大小需小于DEFAULT_SVECTOR_SIZE,否则会抛出异常 | ||
| 81 | - //! | ||
| 82 | - explicit SVector(std::size_t size, const T &value = 0) : size_(0) | ||
| 83 | - { | ||
| 84 | - if (CHECK_BOUND && size > DEFAULT_SVECTOR_SIZE) { | ||
| 85 | - throw MaxSizeExceeded(); | ||
| 86 | - } | ||
| 87 | - size_ = size; | ||
| 88 | - for (std::size_t i = 0; i < size_; ++i) { | ||
| 89 | - storage_[i] = value; | ||
| 90 | - } | ||
| 91 | } | 72 | } |
| 92 | - //! \brief 拷贝构造函数,创建一个新的SVector对象并将另一个SVector对象的值复制到新对象 | 73 | + } |
| 93 | - //! | 74 | + //! \brief 带参数的构造函数 |
| 94 | - //! \param other | 75 | + //! |
| 95 | - //! | 76 | + //! \param size |
| 96 | - SVector(const SVector<T> &other) | 77 | + //! \param value |
| 97 | - { | 78 | + //! |
| 98 | - if (other.heap_) { | 79 | + //! \note size大小需小于DEFAULT_SVECTOR_SIZE,否则会抛出异常 |
| 99 | - heap_ = reinterpret_cast<T *>(malloc(other.size_ * sizeof(T))); | 80 | + //! |
| 100 | - if (!heap_) { | 81 | + explicit SVector(std::size_t size, const T& value = 0) : size_(0) { |
| 101 | - throw std::bad_alloc(); | 82 | + if (CHECK_BOUND && size > DEFAULT_SVECTOR_SIZE) { |
| 102 | - } | 83 | + throw MaxSizeExceeded(); |
| 103 | - size_ = other.size_; | 84 | + } |
| 104 | - for (std::size_t i = 0; i < other.size_; ++i) { | 85 | + size_ = size; |
| 105 | - heap_[i] = other.heap_[i]; | 86 | + for (std::size_t i = 0; i < size_; ++i) { |
| 106 | - } | 87 | + storage_[i] = value; |
| 107 | - } else { | 88 | + } |
| 108 | - size_ = other.size_; | 89 | + } |
| 109 | - for (std::size_t i = 0; i < other.size_; ++i) { | 90 | + //! \brief 拷贝构造函数,创建一个新的SVector对象并将另一个SVector对象的值复制到新对象 |
| 110 | - storage_[i] = other.storage_[i]; | 91 | + //! |
| 111 | - } | 92 | + //! \param other |
| 112 | - } | 93 | + //! |
| 94 | + SVector(const SVector<T>& other) { | ||
| 95 | + if (other.heap_) { | ||
| 96 | + heap_ = reinterpret_cast<T*>(malloc(other.size_ * sizeof(T))); | ||
| 97 | + if (!heap_) { | ||
| 98 | + throw std::bad_alloc(); | ||
| 99 | + } | ||
| 100 | + size_ = other.size_; | ||
| 101 | + for (std::size_t i = 0; i < other.size_; ++i) { | ||
| 102 | + heap_[i] = other.heap_[i]; | ||
| 103 | + } | ||
| 104 | + } else { | ||
| 105 | + size_ = other.size_; | ||
| 106 | + for (std::size_t i = 0; i < other.size_; ++i) { | ||
| 107 | + storage_[i] = other.storage_[i]; | ||
| 108 | + } | ||
| 109 | + } | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + ~SVector() { | ||
| 113 | + if (heap_) { | ||
| 114 | + free(heap_); | ||
| 115 | + } | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + //! \brief 插入元素到指定容器 | ||
| 119 | + //! | ||
| 120 | + //! \param val | ||
| 121 | + //! | ||
| 122 | + //! \note 待添加SVector内元素必须小于SVector容量,否则会抛出异常 | ||
| 123 | + //! | ||
| 124 | + void push_back(const T& val) noexcept((!CHECK_BOUND) && std::is_nothrow_assignable<T, const T&>::value) { | ||
| 125 | + if (heap_) { | ||
| 126 | + if (CHECK_BOUND && size_ == capacity_) { | ||
| 127 | + throw MaxSizeExceeded(); | ||
| 128 | + } | ||
| 129 | + heap_[size_++] = val; | ||
| 130 | + return; | ||
| 131 | + } | ||
| 132 | + if (CHECK_BOUND && size_ == DEFAULT_SVECTOR_SIZE) { | ||
| 133 | + throw MaxSizeExceeded(); | ||
| 134 | + } | ||
| 135 | + storage_[size_++] = val; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + //! \brief 获取容器起始元素地址 | ||
| 139 | + //! | ||
| 140 | + //! \return 指针 | ||
| 141 | + //! | ||
| 142 | + T* begin() noexcept { | ||
| 143 | + if (heap_) { | ||
| 144 | + return &heap_[0]; | ||
| 145 | + } | ||
| 146 | + return &storage_[0]; | ||
| 147 | + } | ||
| 148 | + | ||
| 149 | + //! \brief 获取容器起始元素地址 | ||
| 150 | + //! | ||
| 151 | + //! \return 常量指针 | ||
| 152 | + //! | ||
| 153 | + const T* begin() const noexcept { | ||
| 154 | + if (heap_) { | ||
| 155 | + return &heap_[0]; | ||
| 156 | + } | ||
| 157 | + return &storage_[0]; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + //! \brief 获取容器尾元素地址 | ||
| 161 | + //! | ||
| 162 | + //! \return 指针 | ||
| 163 | + //! | ||
| 164 | + T* end() noexcept { | ||
| 165 | + if (heap_) { | ||
| 166 | + return (&heap_[0]) + size_; | ||
| 167 | + } | ||
| 168 | + return (&storage_[0]) + size_; | ||
| 169 | + } | ||
| 170 | + | ||
| 171 | + //! \brief 获取容器尾地址 | ||
| 172 | + //! | ||
| 173 | + //! \return 常量指针 | ||
| 174 | + //! | ||
| 175 | + const T* end() const noexcept { | ||
| 176 | + if (heap_) { | ||
| 177 | + return (&heap_[0]) + size_; | ||
| 178 | + } | ||
| 179 | + return (&storage_[0]) + size_; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + //! \brief 访问指定位置的元素 | ||
| 183 | + //! | ||
| 184 | + //! \param i | ||
| 185 | + //! | ||
| 186 | + //! \return 引用 | ||
| 187 | + //! | ||
| 188 | + T& operator[](std::size_t i) { | ||
| 189 | + if (heap_) { | ||
| 190 | + if (size_ == 0 || i >= size_) { | ||
| 191 | + throw std::out_of_range("out of range"); | ||
| 192 | + } | ||
| 193 | + return heap_[i]; | ||
| 194 | + } | ||
| 195 | + if (size_ == 0 || i >= size_) { | ||
| 196 | + throw std::out_of_range("out of range"); | ||
| 197 | + } | ||
| 198 | + return storage_[i]; | ||
| 199 | + } | ||
| 200 | + | ||
| 201 | + //! \brief 访问指定位置的元素 | ||
| 202 | + //! | ||
| 203 | + //! \param i | ||
| 204 | + //! | ||
| 205 | + //! \return 常量引用 | ||
| 206 | + //! | ||
| 207 | + const T& operator[](std::size_t i) const { | ||
| 208 | + if (heap_) { | ||
| 209 | + if (size_ == 0 || i >= size_) { | ||
| 210 | + throw std::out_of_range("out of range"); | ||
| 211 | + } | ||
| 212 | + return heap_[i]; | ||
| 213 | + } | ||
| 214 | + if (size_ == 0 || i >= size_) { | ||
| 215 | + throw std::out_of_range("out of range"); | ||
| 216 | + } | ||
| 217 | + return storage_[i]; | ||
| 218 | + } | ||
| 219 | + | ||
| 220 | + //! \brief 访问指定位置的元素 | ||
| 221 | + //! | ||
| 222 | + //! \param i | ||
| 223 | + //! | ||
| 224 | + //! \return 引用 | ||
| 225 | + //! | ||
| 226 | + T& at(std::size_t i) { | ||
| 227 | + if (heap_) { | ||
| 228 | + if (size_ == 0 || i >= size_) { | ||
| 229 | + throw std::out_of_range("out of range"); | ||
| 230 | + } | ||
| 231 | + return heap_[i]; | ||
| 232 | + } else { | ||
| 233 | + if (size_ == 0 || i >= size_ || i > DEFAULT_SVECTOR_SIZE) { | ||
| 234 | + throw std::out_of_range("out of range"); | ||
| 235 | + } | ||
| 236 | + return storage_[i]; | ||
| 237 | + } | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + //! \brief 访问指定位置的元素 | ||
| 241 | + //! | ||
| 242 | + //! \param i | ||
| 243 | + //! | ||
| 244 | + //! \return 引用 | ||
| 245 | + //! | ||
| 246 | + const T& at(std::size_t i) const { | ||
| 247 | + if (heap_) { | ||
| 248 | + if (size_ == 0 || i >= size_) { | ||
| 249 | + throw std::out_of_range("heap out of range"); | ||
| 250 | + } | ||
| 251 | + return heap_[i]; | ||
| 252 | + } | ||
| 253 | + if (size_ == 0 || i >= size_ || i > DEFAULT_SVECTOR_SIZE) { | ||
| 254 | + throw std::out_of_range("stack out of range"); | ||
| 255 | + } | ||
| 256 | + return storage_[i]; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + //! \brief 获取容器的大小 | ||
| 260 | + //! | ||
| 261 | + //! \return size | ||
| 262 | + //! | ||
| 263 | + std::size_t size() const noexcept { | ||
| 264 | + return size_; | ||
| 265 | + } | ||
| 266 | + | ||
| 267 | + //! \brief 向容器内指定位置插入元素 | ||
| 268 | + //! | ||
| 269 | + //! \param pos | ||
| 270 | + //! \param value | ||
| 271 | + //! | ||
| 272 | + //! \note pos必须小于SVector容量,否则会抛出异常 | ||
| 273 | + //! | ||
| 274 | + void insert(const std::size_t pos, const T& value) noexcept( | ||
| 275 | + (!CHECK_BOUND) && std::is_nothrow_assignable<T, const T&>::value) { | ||
| 276 | + if (heap_) { | ||
| 277 | + if (pos > size_ || pos == capacity_) { | ||
| 278 | + throw MaxSizeExceeded(); | ||
| 279 | + } | ||
| 280 | + for (auto it = size_; it != pos; it--) { | ||
| 281 | + heap_[it] = heap_[it - 1]; | ||
| 282 | + } | ||
| 283 | + heap_[pos] = value; | ||
| 284 | + size_ += 1; | ||
| 285 | + return; | ||
| 286 | + } | ||
| 287 | + if (CHECK_BOUND && size_ == DEFAULT_SVECTOR_SIZE) { | ||
| 288 | + throw MaxSizeExceeded(); | ||
| 289 | + } | ||
| 290 | + if (pos > size_) { | ||
| 291 | + throw MaxSizeExceeded(); | ||
| 113 | } | 292 | } |
| 114 | 293 | ||
| 115 | - ~SVector() | 294 | + for (auto it = size_; it != pos; it--) { |
| 116 | - { | 295 | + storage_[it] = storage_[it - 1]; |
| 117 | - if (heap_) { | 296 | + } |
| 118 | - free(heap_); | 297 | + storage_[pos] = value; |
| 119 | - } | 298 | + size_ += 1; |
| 299 | + return; | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + //! \brief 判断容器是否为空 | ||
| 303 | + //! | ||
| 304 | + //! \return bool值 | ||
| 305 | + //! | ||
| 306 | + bool empty() const noexcept { | ||
| 307 | + return size_ == 0; | ||
| 308 | + } | ||
| 309 | + | ||
| 310 | + //! \brief 清空容器 | ||
| 311 | + void clear() noexcept { | ||
| 312 | + size_ = 0; | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + //! \brief 获取容器起始元素地址 | ||
| 316 | + //! | ||
| 317 | + //! \return 指针 | ||
| 318 | + //! | ||
| 319 | + T* data() noexcept { | ||
| 320 | + if (heap_) { | ||
| 321 | + return &heap_[0]; | ||
| 322 | + } | ||
| 323 | + return &storage_[0]; | ||
| 324 | + } | ||
| 325 | + | ||
| 326 | + //! \brief 获取容器起始元素地址 | ||
| 327 | + //! | ||
| 328 | + //! \return 常量指针 | ||
| 329 | + //! | ||
| 330 | + const T* data() const noexcept { | ||
| 331 | + if (heap_) { | ||
| 332 | + return &heap_[0]; | ||
| 333 | + } | ||
| 334 | + return &storage_[0]; | ||
| 335 | + } | ||
| 336 | + | ||
| 337 | + //! \brief 改变SVector容器大小,不能改变SVector容量 | ||
| 338 | + //! | ||
| 339 | + //! \param size | ||
| 340 | + //! | ||
| 341 | + //! \note 传入size参数不能超过SVector容量,反之,则会抛出异常。 | ||
| 342 | + //! | ||
| 343 | + void resize(std::size_t size) { | ||
| 344 | + if (heap_ && size > capacity_) { | ||
| 345 | + throw MaxSizeExceeded(); | ||
| 346 | + } | ||
| 347 | + size_ = size; | ||
| 348 | + } | ||
| 349 | + | ||
| 350 | + //! \brief 改变SVector容量大小,清空内部数据,并将SVector容量大小定义为size大小 | ||
| 351 | + //! | ||
| 352 | + //! \param size | ||
| 353 | + //! | ||
| 354 | + //! \note | ||
| 355 | + //! 用于预分配内存空间,SVector默认容量为DEFAULT_SVECTOR_SIZE,传入的size需大于DEFAULT_SVECTOR_SIZ且小于MAX_SVECTOR_SIZE,反之,则会抛出异常。 | ||
| 356 | + //! | ||
| 357 | + void reserve(std::size_t size) { | ||
| 358 | + if (size > MAX_SVECTOR_SIZE) { | ||
| 359 | + throw MaxSizeExceeded(); | ||
| 120 | } | 360 | } |
| 121 | 361 | ||
| 122 | - //! \brief 插入元素到指定容器 | 362 | + if (size > DEFAULT_SVECTOR_SIZE) { |
| 123 | - //! | 363 | + if (heap_) { |
| 124 | - //! \param val | 364 | + free(heap_); |
| 125 | - //! | 365 | + } |
| 126 | - //! \note 待添加SVector内元素必须小于SVector容量,否则会抛出异常 | 366 | + heap_ = reinterpret_cast<T*>(malloc(size * sizeof(T))); |
| 127 | - //! | 367 | + if (!heap_) { |
| 128 | - void push_back(const T &val) noexcept((!CHECK_BOUND) && std::is_nothrow_assignable<T, const T &>::value) | 368 | + throw std::bad_alloc(); |
| 129 | - { | 369 | + } |
| 130 | - if (heap_) { | 370 | + for (std::size_t i = 0; i < size; ++i) { |
| 131 | - if (CHECK_BOUND && size_ == capacity_) { | 371 | + heap_[i] = {}; |
| 132 | - throw MaxSizeExceeded(); | 372 | + } |
| 133 | - } | 373 | + capacity_ = size; |
| 134 | - heap_[size_++] = val; | ||
| 135 | - return; | ||
| 136 | - } | ||
| 137 | - if (CHECK_BOUND && size_ == DEFAULT_SVECTOR_SIZE) { | ||
| 138 | - throw MaxSizeExceeded(); | ||
| 139 | - } | ||
| 140 | - storage_[size_++] = val; | ||
| 141 | } | 374 | } |
| 375 | + } | ||
| 142 | 376 | ||
| 143 | - //! \brief 获取容器起始元素地址 | 377 | + //! \brief 判断两个容器中的元素是否全部相同 |
| 144 | - //! | 378 | + //! |
| 145 | - //! \return 指针 | 379 | + //! \param other |
| 146 | - //! | 380 | + //! |
| 147 | - T *begin() noexcept | 381 | + //! \return bool值 |
| 148 | - { | 382 | + //! |
| 149 | - if (heap_) { | 383 | + bool operator==(const SVector<T>& other) const { |
| 150 | - return &heap_[0]; | 384 | + if (heap_) { |
| 385 | + if (size_ != other.size_ || !other.heap_) { | ||
| 386 | + return false; | ||
| 387 | + } | ||
| 388 | + for (size_t i = 0; i < size_; ++i) { | ||
| 389 | + if (heap_[i] != other.heap_[i]) { | ||
| 390 | + return false; | ||
| 151 | } | 391 | } |
| 152 | - return &storage_[0]; | 392 | + } |
| 393 | + } else { | ||
| 394 | + if (size_ != other.size_) { | ||
| 395 | + return false; | ||
| 396 | + } | ||
| 397 | + for (size_t i = 0; i < size_; ++i) { | ||
| 398 | + if (storage_[i] != other.storage_[i]) { | ||
| 399 | + return false; | ||
| 400 | + } | ||
| 401 | + } | ||
| 153 | } | 402 | } |
| 403 | + return true; | ||
| 404 | + } | ||
| 154 | 405 | ||
| 155 | - //! \brief 获取容器起始元素地址 | 406 | + //! \brief 判断两个容器中的元素是否存在不同 |
| 156 | - //! | 407 | + //! |
| 157 | - //! \return 常量指针 | 408 | + //! \param other |
| 158 | - //! | 409 | + //! |
| 159 | - const T *begin() const noexcept | 410 | + //! \return bool值 |
| 160 | - { | 411 | + //! |
| 161 | - if (heap_) { | 412 | + bool operator!=(const SVector<T>& other) const { |
| 162 | - return &heap_[0]; | 413 | + if (heap_) { |
| 163 | - } | 414 | + if (size_ != other.size_ || !other.heap_) { |
| 164 | - return &storage_[0]; | ||
| 165 | - } | ||
| 166 | - | ||
| 167 | - //! \brief 获取容器尾元素地址 | ||
| 168 | - //! | ||
| 169 | - //! \return 指针 | ||
| 170 | - //! | ||
| 171 | - T *end() noexcept | ||
| 172 | - { | ||
| 173 | - if (heap_) { | ||
| 174 | - return (&heap_[0]) + size_; | ||
| 175 | - } | ||
| 176 | - return (&storage_[0]) + size_; | ||
| 177 | - } | ||
| 178 | - | ||
| 179 | - //! \brief 获取容器尾地址 | ||
| 180 | - //! | ||
| 181 | - //! \return 常量指针 | ||
| 182 | - //! | ||
| 183 | - const T *end() const noexcept | ||
| 184 | - { | ||
| 185 | - if (heap_) { | ||
| 186 | - return (&heap_[0]) + size_; | ||
| 187 | - } | ||
| 188 | - return (&storage_[0]) + size_; | ||
| 189 | - } | ||
| 190 | - | ||
| 191 | - //! \brief 访问指定位置的元素 | ||
| 192 | - //! | ||
| 193 | - //! \param i | ||
| 194 | - //! | ||
| 195 | - //! \return 引用 | ||
| 196 | - //! | ||
| 197 | - T &operator[](std::size_t i) | ||
| 198 | - { | ||
| 199 | - if (heap_) { | ||
| 200 | - if (size_ == 0 || i >= size_) { | ||
| 201 | - throw std::out_of_range("out of range"); | ||
| 202 | - } | ||
| 203 | - return heap_[i]; | ||
| 204 | - } | ||
| 205 | - if (size_ == 0 || i >= size_) { | ||
| 206 | - throw std::out_of_range("out of range"); | ||
| 207 | - } | ||
| 208 | - return storage_[i]; | ||
| 209 | - } | ||
| 210 | - | ||
| 211 | - //! \brief 访问指定位置的元素 | ||
| 212 | - //! | ||
| 213 | - //! \param i | ||
| 214 | - //! | ||
| 215 | - //! \return 常量引用 | ||
| 216 | - //! | ||
| 217 | - const T &operator[](std::size_t i) const | ||
| 218 | - { | ||
| 219 | - if (heap_) { | ||
| 220 | - if (size_ == 0 || i >= size_) { | ||
| 221 | - throw std::out_of_range("out of range"); | ||
| 222 | - } | ||
| 223 | - return heap_[i]; | ||
| 224 | - } | ||
| 225 | - if (size_ == 0 || i >= size_) { | ||
| 226 | - throw std::out_of_range("out of range"); | ||
| 227 | - } | ||
| 228 | - return storage_[i]; | ||
| 229 | - } | ||
| 230 | - | ||
| 231 | - //! \brief 访问指定位置的元素 | ||
| 232 | - //! | ||
| 233 | - //! \param i | ||
| 234 | - //! | ||
| 235 | - //! \return 引用 | ||
| 236 | - //! | ||
| 237 | - T &at(std::size_t i) | ||
| 238 | - { | ||
| 239 | - if (heap_) { | ||
| 240 | - if (size_ == 0 || i >= size_) { | ||
| 241 | - throw std::out_of_range("out of range"); | ||
| 242 | - } | ||
| 243 | - return heap_[i]; | ||
| 244 | - } else { | ||
| 245 | - if (size_ == 0 || i >= size_ || i > DEFAULT_SVECTOR_SIZE) { | ||
| 246 | - throw std::out_of_range("out of range"); | ||
| 247 | - } | ||
| 248 | - return storage_[i]; | ||
| 249 | - } | ||
| 250 | - } | ||
| 251 | - | ||
| 252 | - //! \brief 访问指定位置的元素 | ||
| 253 | - //! | ||
| 254 | - //! \param i | ||
| 255 | - //! | ||
| 256 | - //! \return 引用 | ||
| 257 | - //! | ||
| 258 | - const T &at(std::size_t i) const | ||
| 259 | - { | ||
| 260 | - if (heap_) { | ||
| 261 | - if (size_ == 0 || i >= size_) { | ||
| 262 | - throw std::out_of_range("heap out of range"); | ||
| 263 | - } | ||
| 264 | - return heap_[i]; | ||
| 265 | - } | ||
| 266 | - if (size_ == 0 || i >= size_ || i > DEFAULT_SVECTOR_SIZE) { | ||
| 267 | - throw std::out_of_range("stack out of range"); | ||
| 268 | - } | ||
| 269 | - return storage_[i]; | ||
| 270 | - } | ||
| 271 | - | ||
| 272 | - //! \brief 获取容器的大小 | ||
| 273 | - //! | ||
| 274 | - //! \return size | ||
| 275 | - //! | ||
| 276 | - std::size_t size() const noexcept | ||
| 277 | - { | ||
| 278 | - return size_; | ||
| 279 | - } | ||
| 280 | - | ||
| 281 | - //! \brief 向容器内指定位置插入元素 | ||
| 282 | - //! | ||
| 283 | - //! \param pos | ||
| 284 | - //! \param value | ||
| 285 | - //! | ||
| 286 | - //! \note pos必须小于SVector容量,否则会抛出异常 | ||
| 287 | - //! | ||
| 288 | - void insert(const std::size_t pos, | ||
| 289 | - const T &value) noexcept((!CHECK_BOUND) && std::is_nothrow_assignable<T, const T &>::value) | ||
| 290 | - { | ||
| 291 | - if (heap_) { | ||
| 292 | - if (pos > size_ || pos == capacity_) { | ||
| 293 | - throw MaxSizeExceeded(); | ||
| 294 | - } | ||
| 295 | - for (auto it = size_; it != pos; it--) { | ||
| 296 | - heap_[it] = heap_[it - 1]; | ||
| 297 | - } | ||
| 298 | - heap_[pos] = value; | ||
| 299 | - size_ += 1; | ||
| 300 | - return; | ||
| 301 | - } | ||
| 302 | - if (CHECK_BOUND && size_ == DEFAULT_SVECTOR_SIZE) { | ||
| 303 | - throw MaxSizeExceeded(); | ||
| 304 | - } | ||
| 305 | - if (pos > size_) { | ||
| 306 | - throw MaxSizeExceeded(); | ||
| 307 | - } | ||
| 308 | - | ||
| 309 | - for (auto it = size_; it != pos; it--) { | ||
| 310 | - storage_[it] = storage_[it - 1]; | ||
| 311 | - } | ||
| 312 | - storage_[pos] = value; | ||
| 313 | - size_ += 1; | ||
| 314 | - return; | ||
| 315 | - } | ||
| 316 | - | ||
| 317 | - //! \brief 判断容器是否为空 | ||
| 318 | - //! | ||
| 319 | - //! \return bool值 | ||
| 320 | - //! | ||
| 321 | - bool empty() const noexcept | ||
| 322 | - { | ||
| 323 | - return size_ == 0; | ||
| 324 | - } | ||
| 325 | - | ||
| 326 | - //! \brief 清空容器 | ||
| 327 | - void clear() noexcept | ||
| 328 | - { | ||
| 329 | - size_ = 0; | ||
| 330 | - } | ||
| 331 | - | ||
| 332 | - //! \brief 获取容器起始元素地址 | ||
| 333 | - //! | ||
| 334 | - //! \return 指针 | ||
| 335 | - //! | ||
| 336 | - T *data() noexcept | ||
| 337 | - { | ||
| 338 | - if (heap_) { | ||
| 339 | - return &heap_[0]; | ||
| 340 | - } | ||
| 341 | - return &storage_[0]; | ||
| 342 | - } | ||
| 343 | - | ||
| 344 | - //! \brief 获取容器起始元素地址 | ||
| 345 | - //! | ||
| 346 | - //! \return 常量指针 | ||
| 347 | - //! | ||
| 348 | - const T *data() const noexcept | ||
| 349 | - { | ||
| 350 | - if (heap_) { | ||
| 351 | - return &heap_[0]; | ||
| 352 | - } | ||
| 353 | - return &storage_[0]; | ||
| 354 | - } | ||
| 355 | - | ||
| 356 | - //! \brief 改变SVector容器大小,不能改变SVector容量 | ||
| 357 | - //! | ||
| 358 | - //! \param size | ||
| 359 | - //! | ||
| 360 | - //! \note 传入size参数不能超过SVector容量,反之,则会抛出异常。 | ||
| 361 | - //! | ||
| 362 | - void resize(std::size_t size) | ||
| 363 | - { | ||
| 364 | - if (heap_ && size > capacity_) { | ||
| 365 | - throw MaxSizeExceeded(); | ||
| 366 | - } | ||
| 367 | - size_ = size; | ||
| 368 | - } | ||
| 369 | - | ||
| 370 | - //! \brief 改变SVector容量大小,清空内部数据,并将SVector容量大小定义为size大小 | ||
| 371 | - //! | ||
| 372 | - //! \param size | ||
| 373 | - //! | ||
| 374 | - //! \note 用于预分配内存空间,SVector默认容量为DEFAULT_SVECTOR_SIZE,传入的size需大于DEFAULT_SVECTOR_SIZ且小于MAX_SVECTOR_SIZE,反之,则会抛出异常。 | ||
| 375 | - //! | ||
| 376 | - void reserve(std::size_t size) | ||
| 377 | - { | ||
| 378 | - if (size > MAX_SVECTOR_SIZE) { | ||
| 379 | - throw MaxSizeExceeded(); | ||
| 380 | - } | ||
| 381 | - | ||
| 382 | - if (size > DEFAULT_SVECTOR_SIZE) { | ||
| 383 | - if (heap_) { | ||
| 384 | - free(heap_); | ||
| 385 | - } | ||
| 386 | - heap_ = reinterpret_cast<T *>(malloc(size * sizeof(T))); | ||
| 387 | - if (!heap_) { | ||
| 388 | - throw std::bad_alloc(); | ||
| 389 | - } | ||
| 390 | - for (std::size_t i = 0; i < size; ++i) { | ||
| 391 | - heap_[i] = {}; | ||
| 392 | - } | ||
| 393 | - capacity_ = size; | ||
| 394 | - } | ||
| 395 | - } | ||
| 396 | - | ||
| 397 | - //! \brief 判断两个容器中的元素是否全部相同 | ||
| 398 | - //! | ||
| 399 | - //! \param other | ||
| 400 | - //! | ||
| 401 | - //! \return bool值 | ||
| 402 | - //! | ||
| 403 | - bool operator==(const SVector<T> &other) const | ||
| 404 | - { | ||
| 405 | - if (heap_) { | ||
| 406 | - if (size_ != other.size_ || !other.heap_) { | ||
| 407 | - return false; | ||
| 408 | - } | ||
| 409 | - for (size_t i = 0; i < size_; ++i) { | ||
| 410 | - if (heap_[i] != other.heap_[i]) { | ||
| 411 | - return false; | ||
| 412 | - } | ||
| 413 | - } | ||
| 414 | - } else { | ||
| 415 | - if (size_ != other.size_) { | ||
| 416 | - return false; | ||
| 417 | - } | ||
| 418 | - for (size_t i = 0; i < size_; ++i) { | ||
| 419 | - if (storage_[i] != other.storage_[i]) { | ||
| 420 | - return false; | ||
| 421 | - } | ||
| 422 | - } | ||
| 423 | - } | ||
| 424 | return true; | 415 | return true; |
| 425 | - } | 416 | + } |
| 426 | - | 417 | + for (size_t i = 0; i < size_; ++i) { |
| 427 | - //! \brief 判断两个容器中的元素是否存在不同 | 418 | + if (heap_[i] != other.heap_[i]) { |
| 428 | - //! | 419 | + return true; |
| 429 | - //! \param other | ||
| 430 | - //! | ||
| 431 | - //! \return bool值 | ||
| 432 | - //! | ||
| 433 | - bool operator!=(const SVector<T> &other) const | ||
| 434 | - { | ||
| 435 | - if (heap_) { | ||
| 436 | - if (size_ != other.size_ || !other.heap_) { | ||
| 437 | - return true; | ||
| 438 | - } | ||
| 439 | - for (size_t i = 0; i < size_; ++i) { | ||
| 440 | - if (heap_[i] != other.heap_[i]) { | ||
| 441 | - return true; | ||
| 442 | - } | ||
| 443 | - } | ||
| 444 | - } else { | ||
| 445 | - if (size_ != other.size_) { | ||
| 446 | - return true; | ||
| 447 | - } | ||
| 448 | - for (size_t i = 0; i < size_; ++i) { | ||
| 449 | - if (storage_[i] != other.storage_[i]) { | ||
| 450 | - return true; | ||
| 451 | - } | ||
| 452 | - } | ||
| 453 | } | 420 | } |
| 454 | - return false; | 421 | + } |
| 455 | - } | 422 | + } else { |
| 456 | - | 423 | + if (size_ != other.size_) { |
| 457 | - //! \brief 判断一个容器中的元素是否比另一个容器小 | 424 | + return true; |
| 458 | - //! | 425 | + } |
| 459 | - //! \param other | 426 | + for (size_t i = 0; i < size_; ++i) { |
| 460 | - //! | 427 | + if (storage_[i] != other.storage_[i]) { |
| 461 | - //! \return bool值 | 428 | + return true; |
| 462 | - //! | ||
| 463 | - bool operator<(const SVector<T> &other) const | ||
| 464 | - { | ||
| 465 | - if (heap_) { | ||
| 466 | - if (size_ != other.size_ || !other.heap_) { | ||
| 467 | - return size_ < other.size_; | ||
| 468 | - } | ||
| 469 | - for (size_t i = 0; i < size_; ++i) { | ||
| 470 | - if (heap_[i] != other.heap_[i]) { | ||
| 471 | - return heap_[i] < other.heap_[i]; | ||
| 472 | - } | ||
| 473 | - } | ||
| 474 | - } else { | ||
| 475 | - if (size_ != other.size_) { | ||
| 476 | - return size_ < other.size_; | ||
| 477 | - } | ||
| 478 | - for (size_t i = 0; i < size_; ++i) { | ||
| 479 | - if (storage_[i] != other.storage_[i]) { | ||
| 480 | - return storage_[i] < other.storage_[i]; | ||
| 481 | - } | ||
| 482 | - } | ||
| 483 | } | 429 | } |
| 484 | - return false; | 430 | + } |
| 485 | } | 431 | } |
| 432 | + return false; | ||
| 433 | + } | ||
| 486 | 434 | ||
| 487 | - //! \brief 重载运算符函数,将初始化列表中的元素赋值给一个SVector对象 | 435 | + //! \brief 判断一个容器中的元素是否比另一个容器小 |
| 488 | - //! | 436 | + //! |
| 489 | - //! \param list | 437 | + //! \param other |
| 490 | - //! | 438 | + //! |
| 491 | - //! \return 容器引用 | 439 | + //! \return bool值 |
| 492 | - //! | 440 | + //! |
| 493 | - SVector &operator=(std::initializer_list<T> list) | 441 | + bool operator<(const SVector<T>& other) const { |
| 494 | - { | 442 | + if (heap_) { |
| 495 | - if (heap_) { | 443 | + if (size_ != other.size_ || !other.heap_) { |
| 496 | - if (CHECK_BOUND && list.size() > MAX_SVECTOR_SIZE) { | 444 | + return size_ < other.size_; |
| 497 | - throw MaxSizeExceeded(); | 445 | + } |
| 498 | - } | 446 | + for (size_t i = 0; i < size_; ++i) { |
| 499 | - size_ = list.size(); | 447 | + if (heap_[i] != other.heap_[i]) { |
| 500 | - size_t i = 0; | 448 | + return heap_[i] < other.heap_[i]; |
| 501 | - for (auto it = list.begin(); it != list.end() && i < size_; ++it) { | ||
| 502 | - heap_[i++] = *it; | ||
| 503 | - } | ||
| 504 | - return *this; | ||
| 505 | - } else { | ||
| 506 | - if (CHECK_BOUND && list.size() > DEFAULT_SVECTOR_SIZE) { | ||
| 507 | - throw MaxSizeExceeded(); | ||
| 508 | - } | ||
| 509 | - size_ = list.size(); | ||
| 510 | - size_t i = 0; | ||
| 511 | - for (auto it = list.begin(); it != list.end() && i < size_; ++it) { | ||
| 512 | - storage_[i++] = *it; | ||
| 513 | - } | ||
| 514 | - return *this; | ||
| 515 | } | 449 | } |
| 516 | - } | 450 | + } |
| 517 | - | 451 | + } else { |
| 518 | - //! \brief 用一个容器给另一个容器赋值 | 452 | + if (size_ != other.size_) { |
| 519 | - //! | 453 | + return size_ < other.size_; |
| 520 | - //! \param other | 454 | + } |
| 521 | - //! | 455 | + for (size_t i = 0; i < size_; ++i) { |
| 522 | - //! \return 容器引用 | 456 | + if (storage_[i] != other.storage_[i]) { |
| 523 | - //! | 457 | + return storage_[i] < other.storage_[i]; |
| 524 | - SVector &operator=(const SVector &other) | ||
| 525 | - { | ||
| 526 | - if (heap_) { | ||
| 527 | - size_ = other.size_; | ||
| 528 | - for (std::size_t i = 0; i < other.size_; ++i) { | ||
| 529 | - heap_[i] = other.heap_[i]; | ||
| 530 | - } | ||
| 531 | - return *this; | ||
| 532 | - } else { | ||
| 533 | - size_ = other.size_; | ||
| 534 | - for (std::size_t i = 0; i < other.size_; ++i) { | ||
| 535 | - storage_[i] = other.storage_[i]; | ||
| 536 | - } | ||
| 537 | - return *this; | ||
| 538 | } | 458 | } |
| 459 | + } | ||
| 539 | } | 460 | } |
| 461 | + return false; | ||
| 462 | + } | ||
| 540 | 463 | ||
| 541 | -private: | 464 | + //! \brief 重载运算符函数,将初始化列表中的元素赋值给一个SVector对象 |
| 542 | - std::size_t capacity_ = 0; | 465 | + //! |
| 543 | - std::size_t size_ = 0; | 466 | + //! \param list |
| 544 | - T storage_[DEFAULT_SVECTOR_SIZE + 1]; | 467 | + //! |
| 545 | - T *heap_ = nullptr; | 468 | + //! \return 容器引用 |
| 469 | + //! | ||
| 470 | + SVector& operator=(std::initializer_list<T> list) { | ||
| 471 | + if (heap_) { | ||
| 472 | + if (CHECK_BOUND && list.size() > MAX_SVECTOR_SIZE) { | ||
| 473 | + throw MaxSizeExceeded(); | ||
| 474 | + } | ||
| 475 | + size_ = list.size(); | ||
| 476 | + size_t i = 0; | ||
| 477 | + for (auto it = list.begin(); it != list.end() && i < size_; ++it) { | ||
| 478 | + heap_[i++] = *it; | ||
| 479 | + } | ||
| 480 | + return *this; | ||
| 481 | + } else { | ||
| 482 | + if (CHECK_BOUND && list.size() > DEFAULT_SVECTOR_SIZE) { | ||
| 483 | + throw MaxSizeExceeded(); | ||
| 484 | + } | ||
| 485 | + size_ = list.size(); | ||
| 486 | + size_t i = 0; | ||
| 487 | + for (auto it = list.begin(); it != list.end() && i < size_; ++it) { | ||
| 488 | + storage_[i++] = *it; | ||
| 489 | + } | ||
| 490 | + return *this; | ||
| 491 | + } | ||
| 492 | + } | ||
| 493 | + | ||
| 494 | + //! \brief 用一个容器给另一个容器赋值 | ||
| 495 | + //! | ||
| 496 | + //! \param other | ||
| 497 | + //! | ||
| 498 | + //! \return 容器引用 | ||
| 499 | + //! | ||
| 500 | + SVector& operator=(const SVector& other) { | ||
| 501 | + if (heap_) { | ||
| 502 | + size_ = other.size_; | ||
| 503 | + for (std::size_t i = 0; i < other.size_; ++i) { | ||
| 504 | + heap_[i] = other.heap_[i]; | ||
| 505 | + } | ||
| 506 | + return *this; | ||
| 507 | + } else { | ||
| 508 | + size_ = other.size_; | ||
| 509 | + for (std::size_t i = 0; i < other.size_; ++i) { | ||
| 510 | + storage_[i] = other.storage_[i]; | ||
| 511 | + } | ||
| 512 | + return *this; | ||
| 513 | + } | ||
| 514 | + } | ||
| 515 | + | ||
| 516 | + private: | ||
| 517 | + std::size_t capacity_ = 0; | ||
| 518 | + std::size_t size_ = 0; | ||
| 519 | + T storage_[DEFAULT_SVECTOR_SIZE + 1]; | ||
| 520 | + T* heap_ = nullptr; | ||
| 546 | }; | 521 | }; |
| 547 | 522 | ||
| 548 | //! \brief 输出容器中的元素 | 523 | //! \brief 输出容器中的元素 |
| @@ -552,21 +527,21 @@ private: | |||
| 552 | //! | 527 | //! |
| 553 | //! \return 输出流 | 528 | //! \return 输出流 |
| 554 | //! | 529 | //! |
| 555 | -template <class T> std::ostream &operator<<(std::ostream &os, const SVector<T> &svector) | 530 | +template <class T> |
| 556 | -{ | 531 | +std::ostream& operator<<(std::ostream& os, const SVector<T>& svector) { |
| 557 | - if (svector.size() == 0) { | 532 | + if (svector.size() == 0) { |
| 558 | - return os; | ||
| 559 | - } | ||
| 560 | - | ||
| 561 | - std::string str = ","; | ||
| 562 | - for (size_t i = 0; i < svector.size(); ++i) { | ||
| 563 | - os << svector.at(i); | ||
| 564 | - if (i != svector.size() - 1) { | ||
| 565 | - os << str; | ||
| 566 | - } | ||
| 567 | - } | ||
| 568 | - | ||
| 569 | return os; | 533 | return os; |
| 534 | + } | ||
| 535 | + | ||
| 536 | + std::string str = ","; | ||
| 537 | + for (size_t i = 0; i < svector.size(); ++i) { | ||
| 538 | + os << svector.at(i); | ||
| 539 | + if (i != svector.size() - 1) { | ||
| 540 | + os << str; | ||
| 541 | + } | ||
| 542 | + } | ||
| 543 | + | ||
| 544 | + return os; | ||
| 570 | } | 545 | } |
| 571 | } // namespace atb | 546 | } // namespace atb |
| 572 | -#endif | 547 | +#endif |
| @@ -17,11 +17,11 @@ namespace op_plugin { | |||
| 17 | 17 | ||
| 18 | /// When `side` is set it overrides `right` (see torch.searchsorted(side=...)). | 18 | /// When `side` is set it overrides `right` (see torch.searchsorted(side=...)). |
| 19 | /// Invalid `side` and side/right conflicts are handled in searchsorted_pre_check_npu; call this after validate. | 19 | /// Invalid `side` and side/right conflicts are handled in searchsorted_pre_check_npu; call this after validate. |
| 20 | -inline bool resolve_searchsorted_effective_right(bool right, const c10::optional<c10::string_view> &side_opt) { | 20 | +inline bool resolve_searchsorted_effective_right(bool right, const c10::optional<c10::string_view>& side_opt) { |
| 21 | - if (!side_opt.has_value()) { | 21 | + if (!side_opt.has_value()) { |
| 22 | - return right; | 22 | + return right; |
| 23 | - } | 23 | + } |
| 24 | - return *side_opt == "right"; | 24 | + return *side_opt == "right"; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | } // namespace op_plugin | 27 | } // namespace op_plugin |
| @@ -25,127 +25,181 @@ | |||
| 25 | 25 | ||
| 26 | namespace op_plugin { | 26 | namespace op_plugin { |
| 27 | 27 | ||
| 28 | -inline bool searchsorted_dims_matched_before_last_dim(const at::Tensor &boundaries, const at::Tensor &input) { | 28 | +inline bool searchsorted_dims_matched_before_last_dim(const at::Tensor& boundaries, const at::Tensor& input) { |
| 29 | - if (boundaries.dim() != input.dim()) { | 29 | + if (boundaries.dim() != input.dim()) { |
| 30 | - return false; | 30 | + return false; |
| 31 | + } | ||
| 32 | + const auto& dims_bd = boundaries.sizes(); | ||
| 33 | + const auto& dims_in = input.sizes(); | ||
| 34 | + for (int64_t dim = 0; dim + 1 < boundaries.dim(); ++dim) { | ||
| 35 | + if (dims_bd[dim] != dims_in[dim]) { | ||
| 36 | + return false; | ||
| 31 | } | 37 | } |
| 32 | - const auto &dims_bd = boundaries.sizes(); | 38 | + } |
| 33 | - const auto &dims_in = input.sizes(); | 39 | + return true; |
| 34 | - for (int64_t dim = 0; dim + 1 < boundaries.dim(); ++dim) { | ||
| 35 | - if (dims_bd[dim] != dims_in[dim]) { | ||
| 36 | - return false; | ||
| 37 | - } | ||
| 38 | - } | ||
| 39 | - return true; | ||
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | /// Full searchsorted pre_check for Tensor values; `output` may be null to skip out-dtype checks (scalar path). | 42 | /// Full searchsorted pre_check for Tensor values; `output` may be null to skip out-dtype checks (scalar path). |
| 43 | -inline void searchsorted_pre_check_npu(const at::Tensor &boundaries, const at::Tensor &input, const at::Tensor *output, | 43 | +inline void searchsorted_pre_check_npu( |
| 44 | - bool out_int32, bool right, const c10::optional<c10::string_view> &side_opt, | 44 | + const at::Tensor& boundaries, |
| 45 | - const c10::optional<at::Tensor> &sorter_opt) { | 45 | + const at::Tensor& input, |
| 46 | - if (side_opt.has_value()) { | 46 | + const at::Tensor* output, |
| 47 | - c10::string_view side = *side_opt; | 47 | + bool out_int32, |
| 48 | - TORCH_CHECK(side == "left" || side == "right", | 48 | + bool right, |
| 49 | - "torch.searchsorted(): side can only be 'left' or 'right' but got ", std::string(side.data(), side.size())); | 49 | + const c10::optional<c10::string_view>& side_opt, |
| 50 | + const c10::optional<at::Tensor>& sorter_opt) { | ||
| 51 | + if (side_opt.has_value()) { | ||
| 52 | + c10::string_view side = *side_opt; | ||
| 53 | + TORCH_CHECK( | ||
| 54 | + side == "left" || side == "right", | ||
| 55 | + "torch.searchsorted(): side can only be 'left' or 'right' but got ", | ||
| 56 | + std::string(side.data(), side.size())); | ||
| 50 | 57 | ||
| 51 | - TORCH_CHECK(!right || side == "right", | 58 | + TORCH_CHECK( |
| 52 | - "torch.searchsorted(): side and right can't be set to opposites, got side of ", | 59 | + !right || side == "right", |
| 53 | - std::string(side.data(), side.size()), " while right was True"); | 60 | + "torch.searchsorted(): side and right can't be set to opposites, got side of ", |
| 61 | + std::string(side.data(), side.size()), | ||
| 62 | + " while right was True"); | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + TORCH_CHECK( | ||
| 66 | + boundaries.device() == input.device(), | ||
| 67 | + "torch.searchsorted(): boundaries and input value tensors should have same device type, but got " | ||
| 68 | + "boundaries tensor device type ", | ||
| 69 | + boundaries.device(), | ||
| 70 | + " and input value tensor device type ", | ||
| 71 | + input.device()); | ||
| 72 | + | ||
| 73 | + if (sorter_opt.has_value()) { | ||
| 74 | + const at::Tensor& sorter = *sorter_opt; | ||
| 75 | + TORCH_CHECK(sorter.defined(), "torch.searchsorted(): optional sorter was set but the sorter tensor is undefined"); | ||
| 76 | + | ||
| 77 | + TORCH_CHECK( | ||
| 78 | + sorter.device() == boundaries.device(), | ||
| 79 | + "torch.searchsorted(): sorter and boundary tensors should have same device type, but got sorter tensor " | ||
| 80 | + "device type ", | ||
| 81 | + sorter.device(), | ||
| 82 | + " and input value tensor device type ", | ||
| 83 | + boundaries.device()); | ||
| 84 | + | ||
| 85 | + TORCH_CHECK( | ||
| 86 | + sorter.sizes() == boundaries.sizes(), | ||
| 87 | + "torch.searchsorted(): boundary and sorter must have the same size, but got boundary tensor ", | ||
| 88 | + boundaries.sizes(), | ||
| 89 | + "and got sorter tensor ", | ||
| 90 | + sorter.sizes()); | ||
| 91 | + | ||
| 92 | + TORCH_CHECK( | ||
| 93 | + sorter.scalar_type() == at::ScalarType::Long, | ||
| 94 | + "torch.searchsorted(): sorter must be a tensor of long dtype but got dtype ", | ||
| 95 | + sorter.scalar_type()); | ||
| 96 | + | ||
| 97 | + if (sorter.numel() > 0) { | ||
| 98 | + auto minmax = sorter.aminmax(); | ||
| 99 | + int64_t vmin = std::get<0>(minmax).item().toLong(); | ||
| 100 | + int64_t vmax = std::get<1>(minmax).item().toLong(); | ||
| 101 | + TORCH_CHECK(vmin >= 0 && vmax < sorter.sizes().back(), "torch.searchsorted(): sorter index out of range"); | ||
| 54 | } | 102 | } |
| 103 | + } | ||
| 55 | 104 | ||
| 56 | - TORCH_CHECK(boundaries.device() == input.device(), | 105 | + TORCH_CHECK( |
| 57 | - "torch.searchsorted(): boundaries and input value tensors should have same device type, but got " | 106 | + input.dim() > 0 || (input.dim() == 0 && input.numel() == 1 && boundaries.dim() == 1), |
| 58 | - "boundaries tensor device type ", | 107 | + "torch.searchsorted(): input value can be a scalar only when boundaries tensor dimension is 1, but we " |
| 59 | - boundaries.device(), " and input value tensor device type ", input.device()); | 108 | + "got boundaries tensor dim(", |
| 109 | + boundaries.dim(), | ||
| 110 | + ") and input value's dim(", | ||
| 111 | + input.dim(), | ||
| 112 | + ") numel(", | ||
| 113 | + input.numel(), | ||
| 114 | + ")"); | ||
| 60 | 115 | ||
| 61 | - if (sorter_opt.has_value()) { | 116 | + // Python `searchsorted(boundaries, 1)` may bind as a Tensor overload with shape [1] instead of a true |
| 62 | - const at::Tensor &sorter = *sorter_opt; | 117 | + // rank-0 scalar; CPU raises the scalar/boundaries-dim error, not "first N-1 dimensions...". |
| 63 | - TORCH_CHECK( | 118 | + if (boundaries.dim() != 1 && input.numel() == 1 && input.dim() != boundaries.dim()) { |
| 64 | - sorter.defined(), "torch.searchsorted(): optional sorter was set but the sorter tensor is undefined"); | 119 | + TORCH_CHECK( |
| 65 | - | 120 | + false, |
| 66 | - TORCH_CHECK(sorter.device() == boundaries.device(), | ||
| 67 | - "torch.searchsorted(): sorter and boundary tensors should have same device type, but got sorter tensor " | ||
| 68 | - "device type ", | ||
| 69 | - sorter.device(), " and input value tensor device type ", boundaries.device()); | ||
| 70 | - | ||
| 71 | - TORCH_CHECK(sorter.sizes() == boundaries.sizes(), | ||
| 72 | - "torch.searchsorted(): boundary and sorter must have the same size, but got boundary tensor ", | ||
| 73 | - boundaries.sizes(), "and got sorter tensor ", sorter.sizes()); | ||
| 74 | - | ||
| 75 | - TORCH_CHECK(sorter.scalar_type() == at::ScalarType::Long, | ||
| 76 | - "torch.searchsorted(): sorter must be a tensor of long dtype but got dtype ", sorter.scalar_type()); | ||
| 77 | - | ||
| 78 | - if (sorter.numel() > 0) { | ||
| 79 | - auto minmax = sorter.aminmax(); | ||
| 80 | - int64_t vmin = std::get<0>(minmax).item().toLong(); | ||
| 81 | - int64_t vmax = std::get<1>(minmax).item().toLong(); | ||
| 82 | - TORCH_CHECK(vmin >= 0 && vmax < sorter.sizes().back(), "torch.searchsorted(): sorter index out of range"); | ||
| 83 | - } | ||
| 84 | - } | ||
| 85 | - | ||
| 86 | - TORCH_CHECK(input.dim() > 0 || (input.dim() == 0 && input.numel() == 1 && boundaries.dim() == 1), | ||
| 87 | "torch.searchsorted(): input value can be a scalar only when boundaries tensor dimension is 1, but we " | 121 | "torch.searchsorted(): input value can be a scalar only when boundaries tensor dimension is 1, but we " |
| 88 | "got boundaries tensor dim(", | 122 | "got boundaries tensor dim(", |
| 89 | - boundaries.dim(), ") and input value's dim(", input.dim(), ") numel(", input.numel(), ")"); | 123 | + boundaries.dim(), |
| 124 | + ") and input value's dim(", | ||
| 125 | + input.dim(), | ||
| 126 | + ") numel(", | ||
| 127 | + input.numel(), | ||
| 128 | + ")"); | ||
| 129 | + } | ||
| 90 | 130 | ||
| 91 | - // Python `searchsorted(boundaries, 1)` may bind as a Tensor overload with shape [1] instead of a true | 131 | + TORCH_CHECK( |
| 92 | - // rank-0 scalar; CPU raises the scalar/boundaries-dim error, not "first N-1 dimensions...". | 132 | + boundaries.dim() != 0, |
| 93 | - if (boundaries.dim() != 1 && input.numel() == 1 && input.dim() != boundaries.dim()) { | 133 | + "torch.searchsorted(): boundaries tensor should have positive dimension, but got 0 dimension"); |
| 94 | - TORCH_CHECK(false, | ||
| 95 | - "torch.searchsorted(): input value can be a scalar only when boundaries tensor dimension is 1, but we " | ||
| 96 | - "got boundaries tensor dim(", | ||
| 97 | - boundaries.dim(), ") and input value's dim(", input.dim(), ") numel(", input.numel(), ")"); | ||
| 98 | - } | ||
| 99 | 134 | ||
| 100 | - TORCH_CHECK(boundaries.dim() != 0, | 135 | + TORCH_CHECK( |
| 101 | - "torch.searchsorted(): boundaries tensor should have positive dimension, but got 0 dimension"); | 136 | + boundaries.dim() == 1 || searchsorted_dims_matched_before_last_dim(boundaries, input), |
| 137 | + "torch.searchsorted(): boundaries tensor should be 1 dimension or the first N-1 dimensions of boundaries " | ||
| 138 | + "tensor and input value tensor must match, but we got boundaries tensor ", | ||
| 139 | + boundaries.sizes(), | ||
| 140 | + " and input value tensor ", | ||
| 141 | + input.sizes()); | ||
| 102 | 142 | ||
| 103 | - TORCH_CHECK(boundaries.dim() == 1 || searchsorted_dims_matched_before_last_dim(boundaries, input), | 143 | + if (output != nullptr) { |
| 104 | - "torch.searchsorted(): boundaries tensor should be 1 dimension or the first N-1 dimensions of boundaries " | 144 | + at::ScalarType output_dtype = output->scalar_type(); |
| 105 | - "tensor and input value tensor must match, but we got boundaries tensor ", | 145 | + TORCH_CHECK( |
| 106 | - boundaries.sizes(), " and input value tensor ", input.sizes()); | 146 | + (output_dtype == at::ScalarType::Long && !out_int32) || (output_dtype == at::ScalarType::Int && out_int32), |
| 147 | + "torch.searchsorted(): output tensor's dtype is wrong, it can only be Int(int32) or Long(int64) " | ||
| 148 | + "depending on whether out_int32 flag is True, but we got output tensor's dtype ", | ||
| 149 | + output_dtype, | ||
| 150 | + " and out_int32 flag is ", | ||
| 151 | + (out_int32 ? "True" : "False")); | ||
| 152 | + } | ||
| 107 | 153 | ||
| 108 | - if (output != nullptr) { | 154 | + if (out_int32) { |
| 109 | - at::ScalarType output_dtype = output->scalar_type(); | 155 | + TORCH_CHECK( |
| 110 | - TORCH_CHECK( | 156 | + boundaries.sizes().back() < INT_MAX, |
| 111 | - (output_dtype == at::ScalarType::Long && !out_int32) || (output_dtype == at::ScalarType::Int && out_int32), | 157 | + "torch.searchsorted(): the size of boundaries' last dimension should be less than ", |
| 112 | - "torch.searchsorted(): output tensor's dtype is wrong, it can only be Int(int32) or Long(int64) " | 158 | + INT_MAX, |
| 113 | - "depending on whether out_int32 flag is True, but we got output tensor's dtype ", | 159 | + ", but we got ", |
| 114 | - output_dtype, " and out_int32 flag is ", (out_int32 ? "True" : "False")); | 160 | + boundaries.sizes().back()); |
| 115 | - } | 161 | + } |
| 116 | - | ||
| 117 | - if (out_int32) { | ||
| 118 | - TORCH_CHECK(boundaries.sizes().back() < INT_MAX, | ||
| 119 | - "torch.searchsorted(): the size of boundaries' last dimension should be less than ", INT_MAX, | ||
| 120 | - ", but we got ", boundaries.sizes().back()); | ||
| 121 | - } | ||
| 122 | } | 162 | } |
| 123 | 163 | ||
| 124 | /// Functional Tensor overload: `out` is created after new_params in generated op_api, so validate everything | 164 | /// Functional Tensor overload: `out` is created after new_params in generated op_api, so validate everything |
| 125 | /// except output dtype here (matches CPU before aclnn). Tensor_out uses searchsorted_validate_tensor_out_op. | 165 | /// except output dtype here (matches CPU before aclnn). Tensor_out uses searchsorted_validate_tensor_out_op. |
| 126 | -inline int searchsorted_validate_core_no_output(const at::Tensor &sorted_sequence, const at::Tensor &self, | 166 | +inline int searchsorted_validate_core_no_output( |
| 127 | - bool out_int32, bool right, const c10::optional<c10::string_view> &side_opt, | 167 | + const at::Tensor& sorted_sequence, |
| 128 | - const c10::optional<at::Tensor> &sorter_opt) { | 168 | + const at::Tensor& self, |
| 129 | - searchsorted_pre_check_npu(sorted_sequence, self, nullptr, out_int32, right, side_opt, sorter_opt); | 169 | + bool out_int32, |
| 130 | - return 0; | 170 | + bool right, |
| 171 | + const c10::optional<c10::string_view>& side_opt, | ||
| 172 | + const c10::optional<at::Tensor>& sorter_opt) { | ||
| 173 | + searchsorted_pre_check_npu(sorted_sequence, self, nullptr, out_int32, right, side_opt, sorter_opt); | ||
| 174 | + return 0; | ||
| 131 | } | 175 | } |
| 132 | 176 | ||
| 133 | /// Tensor_out / same shapes as aclnnSearchSorted. Returns 0 for use in yaml new_params. | 177 | /// Tensor_out / same shapes as aclnnSearchSorted. Returns 0 for use in yaml new_params. |
| 134 | -inline int searchsorted_validate_tensor_out_op(const at::Tensor &sorted_sequence, const at::Tensor &self, | 178 | +inline int searchsorted_validate_tensor_out_op( |
| 135 | - const at::Tensor &out, bool out_int32, bool right, const c10::optional<c10::string_view> &side_opt, | 179 | + const at::Tensor& sorted_sequence, |
| 136 | - const c10::optional<at::Tensor> &sorter_opt) { | 180 | + const at::Tensor& self, |
| 137 | - searchsorted_pre_check_npu(sorted_sequence, self, &out, out_int32, right, side_opt, sorter_opt); | 181 | + const at::Tensor& out, |
| 138 | - return 0; | 182 | + bool out_int32, |
| 183 | + bool right, | ||
| 184 | + const c10::optional<c10::string_view>& side_opt, | ||
| 185 | + const c10::optional<at::Tensor>& sorter_opt) { | ||
| 186 | + searchsorted_pre_check_npu(sorted_sequence, self, &out, out_int32, right, side_opt, sorter_opt); | ||
| 187 | + return 0; | ||
| 139 | } | 188 | } |
| 140 | 189 | ||
| 141 | /// Scalar value: materialize wrapped-number tensor like aten (no output-dtype check; out is created by kernel). | 190 | /// Scalar value: materialize wrapped-number tensor like aten (no output-dtype check; out is created by kernel). |
| 142 | -inline int searchsorted_validate_scalar_op(const at::Tensor &sorted_sequence, const c10::Scalar &self, bool out_int32, | 191 | +inline int searchsorted_validate_scalar_op( |
| 143 | - bool right, const c10::optional<c10::string_view> &side_opt, const c10::optional<at::Tensor> &sorter_opt) { | 192 | + const at::Tensor& sorted_sequence, |
| 144 | - at::Tensor input_t = at::empty({}, sorted_sequence.options()); | 193 | + const c10::Scalar& self, |
| 145 | - input_t.fill_(self); | 194 | + bool out_int32, |
| 146 | - input_t.unsafeGetTensorImpl()->set_wrapped_number(true); | 195 | + bool right, |
| 147 | - searchsorted_pre_check_npu(sorted_sequence, input_t, nullptr, out_int32, right, side_opt, sorter_opt); | 196 | + const c10::optional<c10::string_view>& side_opt, |
| 148 | - return 0; | 197 | + const c10::optional<at::Tensor>& sorter_opt) { |
| 198 | + at::Tensor input_t = at::empty({}, sorted_sequence.options()); | ||
| 199 | + input_t.fill_(self); | ||
| 200 | + input_t.unsafeGetTensorImpl()->set_wrapped_number(true); | ||
| 201 | + searchsorted_pre_check_npu(sorted_sequence, input_t, nullptr, out_int32, right, side_opt, sorter_opt); | ||
| 202 | + return 0; | ||
| 149 | } | 203 | } |
| 150 | 204 | ||
| 151 | } // namespace op_plugin | 205 | } // namespace op_plugin |
| @@ -21,79 +21,82 @@ namespace op_plugin { | |||
| 21 | /// Row-major contiguous check aligned with dense strided layout (matches TensorImpl contiguous semantics). | 21 | /// Row-major contiguous check aligned with dense strided layout (matches TensorImpl contiguous semantics). |
| 22 | /// Some backends may report is_contiguous() true while strides still require an explicit copy for aclnn; this | 22 | /// Some backends may report is_contiguous() true while strides still require an explicit copy for aclnn; this |
| 23 | /// catches permute().to(...) cases that CPU flags in searchsorted_maybe_trim_input_tensors. | 23 | /// catches permute().to(...) cases that CPU flags in searchsorted_maybe_trim_input_tensors. |
| 24 | -inline bool searchsorted_tensor_is_row_major_contiguous(const at::Tensor &t) { | 24 | +inline bool searchsorted_tensor_is_row_major_contiguous(const at::Tensor& t) { |
| 25 | - if (!t.defined() || t.numel() == 0) { | 25 | + if (!t.defined() || t.numel() == 0) { |
| 26 | - return true; | ||
| 27 | - } | ||
| 28 | - if (t.layout() != c10::Layout::Strided) { | ||
| 29 | - return t.is_contiguous(); | ||
| 30 | - } | ||
| 31 | - const int64_t dim = t.dim(); | ||
| 32 | - if (dim == 0) { | ||
| 33 | - return true; | ||
| 34 | - } | ||
| 35 | - int64_t z = 1; | ||
| 36 | - for (int64_t d = dim - 1; d >= 0; --d) { | ||
| 37 | - const int64_t size_d = t.size(d); | ||
| 38 | - if (size_d != 1) { | ||
| 39 | - if (t.stride(d) != z) { | ||
| 40 | - return false; | ||
| 41 | - } | ||
| 42 | - if (size_d == 0) { | ||
| 43 | - return true; | ||
| 44 | - } | ||
| 45 | - } | ||
| 46 | - z *= size_d; | ||
| 47 | - } | ||
| 48 | return true; | 26 | return true; |
| 27 | + } | ||
| 28 | + if (t.layout() != c10::Layout::Strided) { | ||
| 29 | + return t.is_contiguous(); | ||
| 30 | + } | ||
| 31 | + const int64_t dim = t.dim(); | ||
| 32 | + if (dim == 0) { | ||
| 33 | + return true; | ||
| 34 | + } | ||
| 35 | + int64_t z = 1; | ||
| 36 | + for (int64_t d = dim - 1; d >= 0; --d) { | ||
| 37 | + const int64_t size_d = t.size(d); | ||
| 38 | + if (size_d != 1) { | ||
| 39 | + if (t.stride(d) != z) { | ||
| 40 | + return false; | ||
| 41 | + } | ||
| 42 | + if (size_d == 0) { | ||
| 43 | + return true; | ||
| 44 | + } | ||
| 45 | + } | ||
| 46 | + z *= size_d; | ||
| 47 | + } | ||
| 48 | + return true; | ||
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | /// Tensor, Tensor overload: warn once per process when inputs may need a contiguous copy (matches CPU/CUDA). | 51 | /// Tensor, Tensor overload: warn once per process when inputs may need a contiguous copy (matches CPU/CUDA). |
| 52 | inline int warn_if_searchsorted_inputs_noncontiguous( | 52 | inline int warn_if_searchsorted_inputs_noncontiguous( |
| 53 | - const at::Tensor &sorted_sequence, const at::Tensor &self, const c10::optional<at::Tensor> &sorter_opt) { | 53 | + const at::Tensor& sorted_sequence, |
| 54 | - if (!searchsorted_tensor_is_row_major_contiguous(self)) { | 54 | + const at::Tensor& self, |
| 55 | - TORCH_WARN_ONCE( | 55 | + const c10::optional<at::Tensor>& sorter_opt) { |
| 56 | - "torch.searchsorted(): input value tensor is non-contiguous, this will lower the performance due " | 56 | + if (!searchsorted_tensor_is_row_major_contiguous(self)) { |
| 57 | - "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous input value " | 57 | + TORCH_WARN_ONCE( |
| 58 | - "tensor if possible. This message will only appear once per program."); | 58 | + "torch.searchsorted(): input value tensor is non-contiguous, this will lower the performance due " |
| 59 | + "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous input value " | ||
| 60 | + "tensor if possible. This message will only appear once per program."); | ||
| 61 | + } | ||
| 62 | + if (!searchsorted_tensor_is_row_major_contiguous(sorted_sequence)) { | ||
| 63 | + TORCH_WARN_ONCE( | ||
| 64 | + "torch.searchsorted(): boundary tensor is non-contiguous, this will lower the performance due " | ||
| 65 | + "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous boundary " | ||
| 66 | + "tensor if possible. This message will only appear once per program."); | ||
| 67 | + } | ||
| 68 | + if (sorter_opt.has_value()) { | ||
| 69 | + const at::Tensor& st = *sorter_opt; | ||
| 70 | + if (st.defined() && !searchsorted_tensor_is_row_major_contiguous(st)) { | ||
| 71 | + TORCH_WARN_ONCE( | ||
| 72 | + "torch.searchsorted(): sorter tensor is non-contiguous, this will lower the performance due " | ||
| 73 | + "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous sorter " | ||
| 74 | + "tensor if possible. This message will only appear once per program."); | ||
| 59 | } | 75 | } |
| 60 | - if (!searchsorted_tensor_is_row_major_contiguous(sorted_sequence)) { | 76 | + } |
| 61 | - TORCH_WARN_ONCE( | 77 | + return 0; |
| 62 | - "torch.searchsorted(): boundary tensor is non-contiguous, this will lower the performance due " | ||
| 63 | - "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous boundary " | ||
| 64 | - "tensor if possible. This message will only appear once per program."); | ||
| 65 | - } | ||
| 66 | - if (sorter_opt.has_value()) { | ||
| 67 | - const at::Tensor &st = *sorter_opt; | ||
| 68 | - if (st.defined() && !searchsorted_tensor_is_row_major_contiguous(st)) { | ||
| 69 | - TORCH_WARN_ONCE( | ||
| 70 | - "torch.searchsorted(): sorter tensor is non-contiguous, this will lower the performance due " | ||
| 71 | - "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous sorter " | ||
| 72 | - "tensor if possible. This message will only appear once per program."); | ||
| 73 | - } | ||
| 74 | - } | ||
| 75 | - return 0; | ||
| 76 | } | 78 | } |
| 77 | 79 | ||
| 78 | /// Tensor, Scalar overload: only boundaries / sorter apply (scalar value is materialized separately). | 80 | /// Tensor, Scalar overload: only boundaries / sorter apply (scalar value is materialized separately). |
| 79 | inline int warn_if_searchsorted_scalar_inputs_noncontiguous( | 81 | inline int warn_if_searchsorted_scalar_inputs_noncontiguous( |
| 80 | - const at::Tensor &sorted_sequence, const c10::optional<at::Tensor> &sorter_opt) { | 82 | + const at::Tensor& sorted_sequence, |
| 81 | - if (!searchsorted_tensor_is_row_major_contiguous(sorted_sequence)) { | 83 | + const c10::optional<at::Tensor>& sorter_opt) { |
| 82 | - TORCH_WARN_ONCE( | 84 | + if (!searchsorted_tensor_is_row_major_contiguous(sorted_sequence)) { |
| 83 | - "torch.searchsorted(): boundary tensor is non-contiguous, this will lower the performance due " | 85 | + TORCH_WARN_ONCE( |
| 84 | - "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous boundary " | 86 | + "torch.searchsorted(): boundary tensor is non-contiguous, this will lower the performance due " |
| 85 | - "tensor if possible. This message will only appear once per program."); | 87 | + "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous boundary " |
| 88 | + "tensor if possible. This message will only appear once per program."); | ||
| 89 | + } | ||
| 90 | + if (sorter_opt.has_value()) { | ||
| 91 | + const at::Tensor& st = *sorter_opt; | ||
| 92 | + if (st.defined() && !searchsorted_tensor_is_row_major_contiguous(st)) { | ||
| 93 | + TORCH_WARN_ONCE( | ||
| 94 | + "torch.searchsorted(): sorter tensor is non-contiguous, this will lower the performance due " | ||
| 95 | + "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous sorter " | ||
| 96 | + "tensor if possible. This message will only appear once per program."); | ||
| 86 | } | 97 | } |
| 87 | - if (sorter_opt.has_value()) { | 98 | + } |
| 88 | - const at::Tensor &st = *sorter_opt; | 99 | + return 0; |
| 89 | - if (st.defined() && !searchsorted_tensor_is_row_major_contiguous(st)) { | ||
| 90 | - TORCH_WARN_ONCE( | ||
| 91 | - "torch.searchsorted(): sorter tensor is non-contiguous, this will lower the performance due " | ||
| 92 | - "to extra data copy when converting non-contiguous tensor to contiguous, please use contiguous sorter " | ||
| 93 | - "tensor if possible. This message will only appear once per program."); | ||
| 94 | - } | ||
| 95 | - } | ||
| 96 | - return 0; | ||
| 97 | } | 100 | } |
| 98 | 101 | ||
| 99 | } // namespace op_plugin | 102 | } // namespace op_plugin |
| @@ -16,31 +16,30 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | 18 | ||
| 19 | -inline bool correction_fits_aclnn_int64(const c10::optional<c10::Scalar> &correction) | 19 | +inline bool correction_fits_aclnn_int64(const c10::optional<c10::Scalar>& correction) { |
| 20 | -{ | 20 | + if (!correction.has_value()) { |
| 21 | - if (!correction.has_value()) { | ||
| 22 | - return true; | ||
| 23 | - } | ||
| 24 | - const c10::Scalar &s = correction.value(); | ||
| 25 | - if (s.isIntegral(true)) { | ||
| 26 | - return true; | ||
| 27 | - } | ||
| 28 | - if (!s.isFloatingPoint()) { | ||
| 29 | - return false; | ||
| 30 | - } | ||
| 31 | - const double v = s.toDouble(); | ||
| 32 | - if (!std::isfinite(v)) { | ||
| 33 | - return false; | ||
| 34 | - } | ||
| 35 | - const double t = std::trunc(v); | ||
| 36 | - if (v != t) { | ||
| 37 | - return false; | ||
| 38 | - } | ||
| 39 | - if (v > static_cast<double>(std::numeric_limits<int64_t>::max()) || | ||
| 40 | - v < static_cast<double>(std::numeric_limits<int64_t>::min())) { | ||
| 41 | - return false; | ||
| 42 | - } | ||
| 43 | return true; | 21 | return true; |
| 22 | + } | ||
| 23 | + const c10::Scalar& s = correction.value(); | ||
| 24 | + if (s.isIntegral(true)) { | ||
| 25 | + return true; | ||
| 26 | + } | ||
| 27 | + if (!s.isFloatingPoint()) { | ||
| 28 | + return false; | ||
| 29 | + } | ||
| 30 | + const double v = s.toDouble(); | ||
| 31 | + if (!std::isfinite(v)) { | ||
| 32 | + return false; | ||
| 33 | + } | ||
| 34 | + const double t = std::trunc(v); | ||
| 35 | + if (v != t) { | ||
| 36 | + return false; | ||
| 37 | + } | ||
| 38 | + if (v > static_cast<double>(std::numeric_limits<int64_t>::max()) || | ||
| 39 | + v < static_cast<double>(std::numeric_limits<int64_t>::min())) { | ||
| 40 | + return false; | ||
| 41 | + } | ||
| 42 | + return true; | ||
| 44 | } | 43 | } |
| 45 | 44 | ||
| 46 | 45 | ||
| @@ -16,16 +16,10 @@ | |||
| 16 | 16 | ||
| 17 | 17 | ||
| 18 | namespace acl_op { | 18 | namespace acl_op { |
| 19 | -at::Tensor gelu_backward_common_nocheck(const at::Tensor& grad, const at::Tensor& self) | 19 | +at::Tensor gelu_backward_common_nocheck(const at::Tensor& grad, const at::Tensor& self) { |
| 20 | -{ | 20 | + at::Tensor grad_input = at_npu::native::OpPreparation::apply_tensor(self); |
| 21 | - at::Tensor grad_input = at_npu::native::OpPreparation::apply_tensor(self); | 21 | + at_npu::native::OpCommand cmd; |
| 22 | - at_npu::native::OpCommand cmd; | 22 | + cmd.Name("GeluGrad").Input(grad).Input(self).Input(grad).Output(grad_input).Run(); |
| 23 | - cmd.Name("GeluGrad") | 23 | + return grad_input; |
| 24 | - .Input(grad) | ||
| 25 | - .Input(self) | ||
| 26 | - .Input(grad) | ||
| 27 | - .Output(grad_input) | ||
| 28 | - .Run(); | ||
| 29 | - return grad_input; | ||
| 30 | } | 24 | } |
| 31 | } // namespace acl_op | 25 | } // namespace acl_op |
| @@ -21,17 +21,16 @@ at::Tensor& softplus_backward_out_common_nocheck( | |||
| 21 | const at::Tensor& grad_output, | 21 | const at::Tensor& grad_output, |
| 22 | const at::Tensor& self, | 22 | const at::Tensor& self, |
| 23 | at::Scalar beta, | 23 | at::Scalar beta, |
| 24 | - at::Scalar threshold) | 24 | + at::Scalar threshold) { |
| 25 | -{ | 25 | + at_npu::native::OpCommand cmd; |
| 26 | - at_npu::native::OpCommand cmd; | 26 | + cmd.Name("SoftplusV2Grad") |
| 27 | - cmd.Name("SoftplusV2Grad") | 27 | + .Input(grad_output) |
| 28 | - .Input(grad_output) | 28 | + .Input(self) |
| 29 | - .Input(self) | 29 | + .Output(grad_input) |
| 30 | - .Output(grad_input) | 30 | + .Attr("beta", beta) |
| 31 | - .Attr("beta", beta) | 31 | + .Attr("threshold", threshold) |
| 32 | - .Attr("threshold", threshold) | 32 | + .Run(); |
| 33 | - .Run(); | ||
| 34 | 33 | ||
| 35 | - return grad_input; | 34 | + return grad_input; |
| 36 | } | 35 | } |
| 37 | } // namespace acl_op | 36 | } // namespace acl_op |
| @@ -23,35 +23,21 @@ using npu_preparation = at_npu::native::OpPreparation; | |||
| 23 | using npu_utils = at_npu::native::NpuUtils; | 23 | using npu_utils = at_npu::native::NpuUtils; |
| 24 | 24 | ||
| 25 | namespace { | 25 | namespace { |
| 26 | -at::Tensor& sum_out_npu_nocheck( | 26 | +at::Tensor& sum_out_npu_nocheck(at::Tensor& result, const at::Tensor& self, at::IntArrayRef dim, bool keepdim) { |
| 27 | - at::Tensor& result, | 27 | + at::dim_list_to_bitset(dim, self.dim()); |
| 28 | - const at::Tensor& self, | 28 | + c10::SmallVector<int64_t, N> dim_list = |
| 29 | - at::IntArrayRef dim, | 29 | + dim.empty() ? op_plugin::utils::get_dimlist_for_tensor(self) : c10::SmallVector<int64_t, N>(dim); |
| 30 | - bool keepdim) | 30 | + at_npu::native::OpCommand cmd; |
| 31 | -{ | 31 | + cmd.Name("ReduceSum").Input(self).Input(dim_list, at::kLong).Output(result).Attr("keep_dims", keepdim).Run(); |
| 32 | - at::dim_list_to_bitset(dim, self.dim()); | 32 | + return result; |
| 33 | - c10::SmallVector<int64_t, N> dim_list = dim.empty() ? op_plugin::utils::get_dimlist_for_tensor(self) : | ||
| 34 | - c10::SmallVector<int64_t, N>(dim); | ||
| 35 | - at_npu::native::OpCommand cmd; | ||
| 36 | - cmd.Name("ReduceSum") | ||
| 37 | - .Input(self) | ||
| 38 | - .Input(dim_list, at::kLong) | ||
| 39 | - .Output(result) | ||
| 40 | - .Attr("keep_dims", keepdim) | ||
| 41 | - .Run(); | ||
| 42 | - return result; | ||
| 43 | } | 33 | } |
| 44 | 34 | ||
| 45 | -at::Tensor check_dtype( | 35 | +at::Tensor check_dtype(const at::Tensor& self, c10::ScalarType out_type) { |
| 46 | - const at::Tensor &self, | 36 | + if (isIntegralType(out_type, true)) { |
| 47 | - c10::ScalarType out_type) | 37 | + out_type = at::kFloat; |
| 48 | -{ | 38 | + } |
| 49 | - if (isIntegralType(out_type, true)) { | 39 | + at::Tensor self_cp = (self.scalar_type() == out_type) ? self : acl_op::_npu_dtype_cast(self, out_type); |
| 50 | - out_type = at::kFloat; | 40 | + return self_cp; |
| 51 | - } | ||
| 52 | - at::Tensor self_cp = (self.scalar_type() == out_type) ? self : | ||
| 53 | - acl_op::_npu_dtype_cast(self, out_type); | ||
| 54 | - return self_cp; | ||
| 55 | } | 41 | } |
| 56 | } // namespace | 42 | } // namespace |
| 57 | 43 | ||
| @@ -60,72 +46,63 @@ at::Tensor& sum_out_common_nocheck( | |||
| 60 | const at::Tensor& self, | 46 | const at::Tensor& self, |
| 61 | at::IntArrayRef dim, | 47 | at::IntArrayRef dim, |
| 62 | bool keepdim, | 48 | bool keepdim, |
| 63 | - c10::optional<c10::ScalarType> dtype) | 49 | + c10::optional<c10::ScalarType> dtype) { |
| 64 | -{ | 50 | + auto output_size = op_infer::sum_npu_output_size(self, dim, keepdim); |
| 65 | - auto output_size = op_infer::sum_npu_output_size(self, dim, keepdim); | 51 | + auto res_type = dtype.has_value() ? dtype.value() : result.scalar_type(); |
| 66 | - auto res_type = dtype.has_value() ? dtype.value() : result.scalar_type(); | ||
| 67 | 52 | ||
| 68 | - npu_preparation::CheckOut( | 53 | + npu_preparation::CheckOut({self}, result, ACL_FORMAT_ND, res_type, output_size); |
| 69 | - {self}, | ||
| 70 | - result, | ||
| 71 | - ACL_FORMAT_ND, | ||
| 72 | - res_type, | ||
| 73 | - output_size); | ||
| 74 | 54 | ||
| 75 | - if (self.numel() == 0) { | 55 | + if (self.numel() == 0) { |
| 76 | - at::Tensor result_cast = at::empty(output_size, self.options().dtype(res_type)); | 56 | + at::Tensor result_cast = at::empty(output_size, self.options().dtype(res_type)); |
| 77 | - result.copy_(result_cast); | 57 | + result.copy_(result_cast); |
| 78 | - return result; | ||
| 79 | - } | ||
| 80 | - | ||
| 81 | - at::Tensor self_cp = check_dtype(self, res_type); | ||
| 82 | - at::Tensor result_cp = result.scalar_type() == self_cp.scalar_type() ? result : | ||
| 83 | - acl_op::_npu_dtype_cast(result, self_cp.scalar_type()); | ||
| 84 | - if (!npu_utils::check_match(&result_cp)) { | ||
| 85 | - at::Tensor contiguous_result = npu_utils::format_contiguous(result_cp); | ||
| 86 | - sum_out_npu_nocheck(contiguous_result, self_cp, dim, keepdim); | ||
| 87 | - npu_utils::format_fresh_view(result, contiguous_result); | ||
| 88 | - } else { | ||
| 89 | - sum_out_npu_nocheck(result_cp, self_cp, dim, keepdim); | ||
| 90 | - } | ||
| 91 | - | ||
| 92 | - if (result_cp.scalar_type() != res_type) { | ||
| 93 | - result_cp = acl_op::_npu_dtype_cast(result_cp, res_type); | ||
| 94 | - result.copy_(result_cp); | ||
| 95 | - } else { | ||
| 96 | - result = result_cp; | ||
| 97 | - } | ||
| 98 | return result; | 58 | return result; |
| 99 | -} | 59 | + } |
| 100 | 60 | ||
| 61 | + at::Tensor self_cp = check_dtype(self, res_type); | ||
| 62 | + at::Tensor result_cp = | ||
| 63 | + result.scalar_type() == self_cp.scalar_type() ? result : acl_op::_npu_dtype_cast(result, self_cp.scalar_type()); | ||
| 64 | + if (!npu_utils::check_match(&result_cp)) { | ||
| 65 | + at::Tensor contiguous_result = npu_utils::format_contiguous(result_cp); | ||
| 66 | + sum_out_npu_nocheck(contiguous_result, self_cp, dim, keepdim); | ||
| 67 | + npu_utils::format_fresh_view(result, contiguous_result); | ||
| 68 | + } else { | ||
| 69 | + sum_out_npu_nocheck(result_cp, self_cp, dim, keepdim); | ||
| 70 | + } | ||
| 71 | + | ||
| 72 | + if (result_cp.scalar_type() != res_type) { | ||
| 73 | + result_cp = acl_op::_npu_dtype_cast(result_cp, res_type); | ||
| 74 | + result.copy_(result_cp); | ||
| 75 | + } else { | ||
| 76 | + result = result_cp; | ||
| 77 | + } | ||
| 78 | + return result; | ||
| 79 | +} | ||
| 101 | 80 | ||
| 102 | at::Tensor sum_common_nocheck( | 81 | at::Tensor sum_common_nocheck( |
| 103 | const at::Tensor& self, | 82 | const at::Tensor& self, |
| 104 | at::IntArrayRef dim, | 83 | at::IntArrayRef dim, |
| 105 | bool keepdim, | 84 | bool keepdim, |
| 106 | - c10::optional<c10::ScalarType> dtype) | 85 | + c10::optional<c10::ScalarType> dtype) { |
| 107 | -{ | 86 | + auto output_size = op_infer::reduce_ops_npu_output_size(self, dim, keepdim); |
| 108 | - auto output_size = op_infer::reduce_ops_npu_output_size(self, dim, keepdim); | 87 | + auto out_type = self.scalar_type(); |
| 109 | - auto out_type = self.scalar_type(); | ||
| 110 | 88 | ||
| 111 | - if (dtype.has_value()) { | 89 | + if (dtype.has_value()) { |
| 112 | - out_type = dtype.value(); | 90 | + out_type = dtype.value(); |
| 113 | - } else if (isIntegralType(out_type, true)) { | 91 | + } else if (isIntegralType(out_type, true)) { |
| 114 | - out_type = at::kLong; | 92 | + out_type = at::kLong; |
| 115 | - } | 93 | + } |
| 116 | 94 | ||
| 117 | - if (self.numel() == 0) { | 95 | + if (self.numel() == 0) { |
| 118 | - return at::zeros(output_size, self.options().dtype(out_type)); | 96 | + return at::zeros(output_size, self.options().dtype(out_type)); |
| 119 | - } | 97 | + } |
| 120 | 98 | ||
| 121 | - at::Tensor self_cp = check_dtype(self, out_type); | 99 | + at::Tensor self_cp = check_dtype(self, out_type); |
| 122 | - at::Tensor result = npu_preparation::apply_tensor_with_format( | 100 | + at::Tensor result = npu_preparation::apply_tensor_with_format(output_size, self_cp.options(), ACL_FORMAT_ND); |
| 123 | - output_size, self_cp.options(), ACL_FORMAT_ND); | 101 | + sum_out_npu_nocheck(result, self_cp, dim, keepdim); |
| 124 | - sum_out_npu_nocheck(result, self_cp, dim, keepdim); | ||
| 125 | 102 | ||
| 126 | - if (result.scalar_type() != out_type) { | 103 | + if (result.scalar_type() != out_type) { |
| 127 | - result = acl_op::_npu_dtype_cast(result, out_type); | 104 | + result = acl_op::_npu_dtype_cast(result, out_type); |
| 128 | - } | 105 | + } |
| 129 | - return result; | 106 | + return result; |
| 130 | } | 107 | } |
| 131 | } // namespace acl_op | 108 | } // namespace acl_op |
| @@ -20,45 +20,45 @@ | |||
| 20 | namespace op_api { | 20 | namespace op_api { |
| 21 | using npu_preparation = at_npu::native::OpPreparation; | 21 | using npu_preparation = at_npu::native::OpPreparation; |
| 22 | 22 | ||
| 23 | -at::Tensor &sum_out_common_nocheck(const at::Tensor &self, | 23 | +at::Tensor& sum_out_common_nocheck( |
| 24 | - at::IntArrayRef dim, | 24 | + const at::Tensor& self, |
| 25 | - bool keepdim, | 25 | + at::IntArrayRef dim, |
| 26 | - c10::optional<c10::ScalarType> dtype, | 26 | + bool keepdim, |
| 27 | - at::Tensor &result) | 27 | + c10::optional<c10::ScalarType> dtype, |
| 28 | -{ | 28 | + at::Tensor& result) { |
| 29 | - DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum_out(self, dim, keepdim, dtype, result)); | 29 | + DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum_out(self, dim, keepdim, dtype, result)); |
| 30 | - auto output_size = op_infer::sum_npu_output_size(self, dim, keepdim); | 30 | + auto output_size = op_infer::sum_npu_output_size(self, dim, keepdim); |
| 31 | - auto res_type = dtype.has_value() ? dtype.value() : result.scalar_type(); | 31 | + auto res_type = dtype.has_value() ? dtype.value() : result.scalar_type(); |
| 32 | - npu_preparation::check_tensor({self}, result, res_type, output_size); | 32 | + npu_preparation::check_tensor({self}, result, res_type, output_size); |
| 33 | 33 | ||
| 34 | - EXEC_NPU_CMD(aclnnReduceSum, self, dim, keepdim, res_type, result); | 34 | + EXEC_NPU_CMD(aclnnReduceSum, self, dim, keepdim, res_type, result); |
| 35 | - return result; | 35 | + return result; |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | -at::Tensor sum_common_nocheck(const at::Tensor &self, | 38 | +at::Tensor sum_common_nocheck( |
| 39 | - at::IntArrayRef dim, | 39 | + const at::Tensor& self, |
| 40 | - bool keepdim, | 40 | + at::IntArrayRef dim, |
| 41 | - c10::optional<c10::ScalarType> dtype) | 41 | + bool keepdim, |
| 42 | -{ | 42 | + c10::optional<c10::ScalarType> dtype) { |
| 43 | - DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum(self, dim, keepdim, dtype)); | 43 | + DO_COMPATIBILITY(aclnnReduceSum, acl_op::sum(self, dim, keepdim, dtype)); |
| 44 | - auto output_size = op_infer::reduce_ops_npu_output_size(self, dim, keepdim); | 44 | + auto output_size = op_infer::reduce_ops_npu_output_size(self, dim, keepdim); |
| 45 | - auto self_size = self.sizes(); | 45 | + auto self_size = self.sizes(); |
| 46 | - auto out_type = self.scalar_type(); | 46 | + auto out_type = self.scalar_type(); |
| 47 | 47 | ||
| 48 | - if (dtype.has_value()) { | 48 | + if (dtype.has_value()) { |
| 49 | - out_type = dtype.value(); | 49 | + out_type = dtype.value(); |
| 50 | - } else if (isIntegralType(out_type, true)) { | 50 | + } else if (isIntegralType(out_type, true)) { |
| 51 | - out_type = at::kLong; | 51 | + out_type = at::kLong; |
| 52 | + } | ||
| 53 | + | ||
| 54 | + for (uint64_t i = 0; i < self_size.size(); i++) { | ||
| 55 | + if (self_size[i] == 0) { | ||
| 56 | + return at::zeros(output_size, self.options().dtype(out_type)); | ||
| 52 | } | 57 | } |
| 58 | + } | ||
| 53 | 59 | ||
| 54 | - for (uint64_t i = 0; i < self_size.size(); i++) { | 60 | + at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, self.options().dtype(out_type)); |
| 55 | - if (self_size[i] == 0) { | 61 | + EXEC_NPU_CMD(aclnnReduceSum, self, dim, keepdim, out_type, result); |
| 56 | - return at::zeros(output_size, self.options().dtype(out_type)); | 62 | + return result; |
| 57 | - } | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - at::Tensor result = npu_preparation::apply_tensor_without_format(output_size, self.options().dtype(out_type)); | ||
| 61 | - EXEC_NPU_CMD(aclnnReduceSum, self, dim, keepdim, out_type, result); | ||
| 62 | - return result; | ||
| 63 | } | 63 | } |
| 64 | } // namespace op_api | 64 | } // namespace op_api |
| @@ -200,7 +200,7 @@ class TestOpApiCompatibility(TestCase): | |||
| 200 | allow_dict["torch_npu"].extend(allow_dict_info["torch_npu"][version_tag]) | 200 | allow_dict["torch_npu"].extend(allow_dict_info["torch_npu"][version_tag]) |
| 201 | 201 | ||
| 202 | # load torch_npu_OpApi_schema_all.json | 202 | # load torch_npu_OpApi_schema_all.json |
| 203 | - base_schema = {} | 203 | + base_schema = {} |
| 204 | with open(get_file_path_2(os.path.dirname(__file__), "torch_npu_OpApi_schema_all.json")) as fp: | 204 | with open(get_file_path_2(os.path.dirname(__file__), "torch_npu_OpApi_schema_all.json")) as fp: |
| 205 | base_schema0 = json.load(fp) | 205 | base_schema0 = json.load(fp) |
| 206 | for key, value in base_schema0.items(): | 206 | for key, value in base_schema0.items(): |
| @@ -57,13 +57,13 @@ class TestAddmmActivationOut(TestCase): | |||
| 57 | cpu_out = cpu_out.to(torch.float32) | 57 | cpu_out = cpu_out.to(torch.float32) |
| 58 | 58 | ||
| 59 | cpu_out_copy = copy.deepcopy(cpu_out) | 59 | cpu_out_copy = copy.deepcopy(cpu_out) |
| 60 | - cpu_ref = self.cpu_reference_out(cpu_input1, cpu_input2, cpu_input3, | 60 | + cpu_ref = self.cpu_reference_out(cpu_input1, cpu_input2, cpu_input3, |
| 61 | beta, alpha, use_gelu, cpu_out_copy) | 61 | beta, alpha, use_gelu, cpu_out_copy) |
| 62 | - | 62 | + |
| 63 | if dtype == np.float16: | 63 | if dtype == np.float16: |
| 64 | cpu_ref = cpu_ref.astype(np.float16) | 64 | cpu_ref = cpu_ref.astype(np.float16) |
| 65 | - | 65 | + |
| 66 | - npu_res = self.npu_op_exec_out(npu_input1, npu_input2, npu_input3, | 66 | + npu_res = self.npu_op_exec_out(npu_input1, npu_input2, npu_input3, |
| 67 | beta, alpha, use_gelu, npu_out) | 67 | beta, alpha, use_gelu, npu_out) |
| 68 | self.assertRtolEqual(cpu_ref, npu_res, prec=1.e-3, prec16=1.e-3) | 68 | self.assertRtolEqual(cpu_ref, npu_res, prec=1.e-3, prec16=1.e-3) |
| 69 | 69 | ||
| @@ -71,7 +71,7 @@ class TestAddmmActivationOut(TestCase): | |||
| 71 | shape_a = (3, 3) | 71 | shape_a = (3, 3) |
| 72 | shape_b = (3, 4) | 72 | shape_b = (3, 4) |
| 73 | shape_c = (4, 3) | 73 | shape_c = (4, 3) |
| 74 | - | 74 | + |
| 75 | # ReLU 测试 | 75 | # ReLU 测试 |
| 76 | self._run_test(np.float32, shape_a, shape_b, shape_c, 1, (0, 2), False) | 76 | self._run_test(np.float32, shape_a, shape_b, shape_c, 1, (0, 2), False) |
| 77 | # GeLU 测试 | 77 | # GeLU 测试 |
| @@ -81,7 +81,7 @@ class TestAddmmActivationOut(TestCase): | |||
| 81 | shape_a = (3, 3) | 81 | shape_a = (3, 3) |
| 82 | shape_b = (3, 4) | 82 | shape_b = (3, 4) |
| 83 | shape_c = (4, 3) | 83 | shape_c = (4, 3) |
| 84 | - | 84 | + |
| 85 | # ReLU 测试 | 85 | # ReLU 测试 |
| 86 | self._run_test(np.float16, shape_a, shape_b, shape_c, 2, (0, 10), False) | 86 | self._run_test(np.float16, shape_a, shape_b, shape_c, 2, (0, 10), False) |
| 87 | # GeLU 测试 | 87 | # GeLU 测试 |
| @@ -89,4 +89,4 @@ class TestAddmmActivationOut(TestCase): | |||
| 89 | 89 | ||
| 90 | 90 | ||
| 91 | if __name__ == '__main__': | 91 | if __name__ == '__main__': |
| 92 | - run_tests() | 92 | + run_tests() |
| @@ -528,4 +528,4 @@ class TestScaledGroupedMm(TestCase): | |||
| 528 | 528 | ||
| 529 | 529 | ||
| 530 | if __name__ == "__main__": | 530 | if __name__ == "__main__": |
| 531 | - run_tests() | 531 | + run_tests() |
| @@ -667,4 +667,4 @@ class TestScaledGroupedMmV2(TestCase): | |||
| 667 | self.assertTrue(output.device.type == 'npu') | 667 | self.assertTrue(output.device.type == 'npu') |
| 668 | 668 | ||
| 669 | if __name__ == "__main__": | 669 | if __name__ == "__main__": |
| 670 | - run_tests() | 670 | + run_tests() |
| @@ -475,4 +475,4 @@ class TestNPUDequantSwigluQuant(TestCase): | |||
| 475 | 475 | ||
| 476 | 476 | ||
| 477 | if __name__ == "__main__": | 477 | if __name__ == "__main__": |
| 478 | - run_tests() | 478 | + run_tests() |
| @@ -20,12 +20,12 @@ class MoeFinalizeRoutingData: | |||
| 20 | 20 | ||
| 21 | 21 | ||
| 22 | class TestMoeFinalizeRouting(TestCase): | 22 | class TestMoeFinalizeRouting(TestCase): |
| 23 | - | 23 | + |
| 24 | def moe_finalize_routing_np(self, data_struct): | 24 | def moe_finalize_routing_np(self, data_struct): |
| 25 | NK = data_struct.expanded_src_to_dst_row.shape[0] | 25 | NK = data_struct.expanded_src_to_dst_row.shape[0] |
| 26 | K = 1 | 26 | K = 1 |
| 27 | if data_struct.scales is not None: | 27 | if data_struct.scales is not None: |
| 28 | - K = data_struct.scales.shape[1] | 28 | + K = data_struct.scales.shape[1] |
| 29 | num_rows = NK // K | 29 | num_rows = NK // K |
| 30 | H = data_struct.expanded_permuted_rows.shape[-1] | 30 | H = data_struct.expanded_permuted_rows.shape[-1] |
| 31 | expanded_permuted_rows = data_struct.expanded_permuted_rows.reshape(-1, H) | 31 | expanded_permuted_rows = data_struct.expanded_permuted_rows.reshape(-1, H) |
| @@ -45,7 +45,7 @@ class TestMoeFinalizeRouting(TestCase): | |||
| 45 | else: | 45 | else: |
| 46 | dst_row = expanded_permuted_rows[value, :] | 46 | dst_row = expanded_permuted_rows[value, :] |
| 47 | expert_id = data_struct.expert_for_source_row[i, k] | 47 | expert_id = data_struct.expert_for_source_row[i, k] |
| 48 | - | 48 | + |
| 49 | scalesV = 1.0 | 49 | scalesV = 1.0 |
| 50 | if data_struct.scales is not None: | 50 | if data_struct.scales is not None: |
| 51 | scalesV = data_struct.scales[i, k] | 51 | scalesV = data_struct.scales[i, k] |
| @@ -54,7 +54,7 @@ class TestMoeFinalizeRouting(TestCase): | |||
| 54 | else: | 54 | else: |
| 55 | out[i, :] += scalesV * dst_row | 55 | out[i, :] += scalesV * dst_row |
| 56 | return out | 56 | return out |
| 57 | - | 57 | + |
| 58 | def custom_op_exec(self, data_struct): | 58 | def custom_op_exec(self, data_struct): |
| 59 | scales_npu = None | 59 | scales_npu = None |
| 60 | if data_struct.scales is not None: | 60 | if data_struct.scales is not None: |
| @@ -70,7 +70,7 @@ class TestMoeFinalizeRouting(TestCase): | |||
| 70 | torch.tensor(data_struct.expanded_src_to_dst_row).npu(), | 70 | torch.tensor(data_struct.expanded_src_to_dst_row).npu(), |
| 71 | expert_for_source_row_npu, | 71 | expert_for_source_row_npu, |
| 72 | data_struct.drop_pad_mode) | 72 | data_struct.drop_pad_mode) |
| 73 | - | 73 | + |
| 74 | def generate_input_data(self, expert_num=16, token_len=10, top_k=4, num_rows=50): | 74 | def generate_input_data(self, expert_num=16, token_len=10, top_k=4, num_rows=50): |
| 75 | expanded_permuted_rows = np.random.randn(num_rows * top_k, token_len).astype(np.float32) | 75 | expanded_permuted_rows = np.random.randn(num_rows * top_k, token_len).astype(np.float32) |
| 76 | skip1 = np.random.randn(num_rows, token_len).astype(np.float32) | 76 | skip1 = np.random.randn(num_rows, token_len).astype(np.float32) |
| @@ -83,7 +83,7 @@ class TestMoeFinalizeRouting(TestCase): | |||
| 83 | data_struct = MoeFinalizeRoutingData(expanded_permuted_rows, skip1, skip2_optional, bias, scales, | 83 | data_struct = MoeFinalizeRoutingData(expanded_permuted_rows, skip1, skip2_optional, bias, scales, |
| 84 | expanded_src_to_dst_row, expert_for_source_row, 0) | 84 | expanded_src_to_dst_row, expert_for_source_row, 0) |
| 85 | return data_struct | 85 | return data_struct |
| 86 | - | 86 | + |
| 87 | def generate_input_data_drop_pad(self, expert_num=16, token_len=10, c=20, top_k=4, num_rows=50): | 87 | def generate_input_data_drop_pad(self, expert_num=16, token_len=10, c=20, top_k=4, num_rows=50): |
| 88 | expanded_permuted_rows = np.random.randn(expert_num, c, token_len).astype(np.float32) | 88 | expanded_permuted_rows = np.random.randn(expert_num, c, token_len).astype(np.float32) |
| 89 | skip1 = np.random.randn(num_rows, token_len).astype(np.float32) | 89 | skip1 = np.random.randn(num_rows, token_len).astype(np.float32) |
| @@ -96,7 +96,7 @@ class TestMoeFinalizeRouting(TestCase): | |||
| 96 | data_struct = MoeFinalizeRoutingData(expanded_permuted_rows, skip1, skip2_optional, bias, scales, | 96 | data_struct = MoeFinalizeRoutingData(expanded_permuted_rows, skip1, skip2_optional, bias, scales, |
| 97 | expanded_src_to_dst_row, expert_for_source_row, 1) | 97 | expanded_src_to_dst_row, expert_for_source_row, 1) |
| 98 | return data_struct | 98 | return data_struct |
| 99 | - | 99 | + |
| 100 | 100 | ||
| 101 | def test_moe_finalize_routing(self, device="npu"): | 101 | def test_moe_finalize_routing(self, device="npu"): |
| 102 | data_struct = self.generate_input_data(expert_num=16, token_len=5, top_k=4, num_rows=5) | 102 | data_struct = self.generate_input_data(expert_num=16, token_len=5, top_k=4, num_rows=5) |
| @@ -114,4 +114,4 @@ class TestMoeFinalizeRouting(TestCase): | |||
| 114 | self.assertRtolEqual(expected_output, custom_output.cpu().numpy(), 0.0001) | 114 | self.assertRtolEqual(expected_output, custom_output.cpu().numpy(), 0.0001) |
| 115 | 115 | ||
| 116 | if __name__ == "__main__": | 116 | if __name__ == "__main__": |
| 117 | - run_tests() | 117 | + run_tests() |
| @@ -1,5 +1,5 @@ | |||
| 1 | # Copyright (c) 2023 Huawei Technologies Co., Ltd | 1 | # Copyright (c) 2023 Huawei Technologies Co., Ltd |
| 2 | -# Copyright (c) 2019, Facebook CORPORATION. | 2 | +# Copyright (c) 2019, Facebook CORPORATION. |
| 3 | # All rights reserved. | 3 | # All rights reserved. |
| 4 | # | 4 | # |
| 5 | # Licensed under the BSD 3-Clause License (the "License"); | 5 | # Licensed under the BSD 3-Clause License (the "License"); |