#include #include #include #include #include #include #ifndef AT_PER_OPERATOR_HEADERS #include #else #include #endif namespace at { namespace native { namespace vulkan { namespace ops { LayernormPackedContext::LayernormPackedContext( const std::optional& weight, const std::optional& bias, double eps) : unpacked_{c10::AnyType::get()} { packed_.reserve(ListArgs::kNumArgs); TORCH_CHECK(weight, "Weight must be provided!"); packed_.emplace_back(weight->vulkan()); TORCH_CHECK(bias, "Bias must be provided!"); packed_.emplace_back(bias->vulkan()); packed_.emplace_back(eps); if (!at::globalContext().releaseWeightsWhenPrepacking()) { unpacked_.reserve(ListArgs::kNumArgs); unpacked_.emplace_back(weight); unpacked_.emplace_back(bias); unpacked_.emplace_back(eps); } } LayernormPackedContext LayernormPackedContext::pack( c10::impl::GenericList unpacked) { return LayernormPackedContext( get_optional_tensor(unpacked, ListArgs::kWeight), get_optional_tensor(unpacked, ListArgs::kBias), unpacked.get(ListArgs::kEps).toDouble()); } c10::intrusive_ptr create_layernorm_context( std::optional&& weight, std::optional&& bias, double eps) { return c10::make_intrusive( LayernormPackedContext(weight, bias, eps)); } Tensor run_layernorm_context( const Tensor& input_arg, IntArrayRef normalized_shape, const c10::intrusive_ptr& layernorm_context) { const Tensor input = input_arg.is_vulkan() ? input_arg : input_arg.vulkan(); const std::optional& weight_opt = layernorm_context->get_val(LayernormPackedContext::ListArgs::kWeight) .toTensor(); const std::optional& bias_opt = layernorm_context->get_val(LayernormPackedContext::ListArgs::kBias) .toTensor(); const float eps = api::utils::safe_downcast( layernorm_context->get_val(LayernormPackedContext::ListArgs::kEps) .toDouble()); // We invoke native_layer_norm which returns a tuple of tensors: , but we only need the first tensor (layer_norm). std::tuple native_layer_norm_output = at::native_layer_norm(input, normalized_shape, weight_opt, bias_opt, eps); return std::get<0>(native_layer_norm_output); } static Tensor layer_norm( const at::Tensor& input_arg, IntArrayRef normalized_shape, const std::optional& weight_opt /* optional */, const std::optional& bias_opt /* optional */, double eps, bool /* cudnn_enable, deprecated */) { return run_layernorm_context( input_arg, normalized_shape, c10::make_intrusive( LayernormPackedContext(weight_opt, bias_opt, eps))); } #ifdef USE_VULKAN_API TORCH_LIBRARY_IMPL(aten, Vulkan, m) { m.impl(TORCH_SELECTIVE_NAME("aten::layer_norm"), TORCH_FN(layer_norm)); } #endif /* USE_VULKAN_API */ } // namespace ops } // namespace vulkan } // namespace native } // namespace at