main
cpp 71 lines 2.41 KB
Raw
1 #include "cpu_types.hpp"
2
3 #include <array>
4 #include <cstdint>
5 #include <mutex>
6 #include <string>
7
8 #include <ATen/ops/empty.h>
9 #include <ATen/ops/gelu.h>
10 #include <c10/util/BFloat16.h>
11
12 constexpr uint32_t ActivationLutSize = 1u << 16;
13
14 at::Tensor gelu_reference(const at::Tensor& x) { return at::gelu(x, "none"); }
15
16 void maybe_init_activation_lut_bf16(
17 uint16_t* lut, std::once_flag& once,
18 at::Tensor (*activation)(const at::Tensor&)) {
19 std::call_once(once, [&]() {
20 auto lut_input =
21 at::empty({static_cast<int64_t>(ActivationLutSize)},
22 at::TensorOptions().device(at::kCPU).dtype(at::kFloat));
23 auto* lut_input_ptr = lut_input.data_ptr<float>();
24 #pragma omp parallel for
25 for (uint32_t i = 0; i < ActivationLutSize; ++i) {
26 lut_input_ptr[i] = c10::detail::f32_from_bits(static_cast<uint16_t>(i));
27 }
28
29 auto lut_output = activation(lut_input);
30 const auto* lut_output_ptr = lut_output.data_ptr<float>();
31 #pragma omp parallel for
32 for (uint32_t i = 0; i < ActivationLutSize; ++i) {
33 lut[i] = c10::detail::round_to_nearest_even(lut_output_ptr[i]);
34 }
35 });
36 }
37
38 void activation_lut_bf16(torch::Tensor& out, torch::Tensor& input,
39 const uint16_t* lut, const char* op_name) {
40 TORCH_CHECK(input.scalar_type() == at::kBFloat16, op_name,
41 ": input must be bfloat16");
42 TORCH_CHECK(out.scalar_type() == at::kBFloat16, op_name,
43 ": out must be bfloat16");
44 TORCH_CHECK(input.is_contiguous(), op_name, ": input must be contiguous");
45 TORCH_CHECK(out.is_contiguous(), op_name, ": out must be contiguous");
46
47 const auto* src =
48 reinterpret_cast<const uint16_t*>(input.data_ptr<at::BFloat16>());
49 auto* dst = reinterpret_cast<uint16_t*>(out.data_ptr<at::BFloat16>());
50 const int64_t n = input.numel();
51
52 CPU_KERNEL_GUARD_IN(activation_lut_bf16_impl)
53 #pragma omp parallel for
54 for (int64_t i = 0; i < n; ++i) {
55 dst[i] = lut[src[i]];
56 }
57 CPU_KERNEL_GUARD_OUT(activation_lut_bf16_impl)
58 }
59
60 void activation_lut_bf16(torch::Tensor& out, torch::Tensor& input,
61 const std::string& activation) {
62 if (activation == "gelu") {
63 static std::array<uint16_t, ActivationLutSize> lut{};
64 static std::once_flag once;
65 maybe_init_activation_lut_bf16(lut.data(), once, gelu_reference);
66 activation_lut_bf16(out, input, lut.data(), "gelu_lut");
67 return;
68 }
69
70 TORCH_CHECK(false, "Unsupported activation: ", activation);
71 }