Automated PR - 2026-07-07
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
#include <ATen/cuda/CUDAContext.h>
|
||||
#include <c10/cuda/CUDAGuard.h>
|
||||
#include <torch/extension.h>
|
||||
#include <torch/python.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
void fp6_pack_cuda(
|
||||
at::Tensor& x,
|
||||
at::Tensor& out,
|
||||
cudaStream_t stream
|
||||
);
|
||||
|
||||
void fp6_unpack_cuda(
|
||||
at::Tensor& x,
|
||||
at::Tensor& out,
|
||||
cudaStream_t stream
|
||||
);
|
||||
|
||||
at::Tensor fp6_pack(at::Tensor &x) {
|
||||
// TORCH_CHECK(x.dtype() == torch::kUInt8, "Input tensor must be uint8");
|
||||
TORCH_CHECK(x.is_cuda(), "Input tensor must be on CUDA");
|
||||
TORCH_CHECK(x.is_contiguous(), "Input tensor must be contiguous");
|
||||
TORCH_CHECK(x.dim() == 2, "Input tensor must be 2D [m, n]");
|
||||
|
||||
int64_t m = x.size(0);
|
||||
int64_t n = x.size(1);
|
||||
|
||||
TORCH_CHECK(n % 8 == 0, "n must be divisible by 8, got ", n);
|
||||
|
||||
// Output shape: [m, n*3/4] since 4 elements of 8-bit = 32 bits, 4 elements of 6-bit = 24 bits = 3 bytes
|
||||
int64_t n_packed = n * 3 / 4;
|
||||
|
||||
auto options = torch::TensorOptions()
|
||||
.dtype(torch::kUInt8)
|
||||
.device(x.device());
|
||||
|
||||
at::Tensor out = torch::empty({m, n_packed}, options);
|
||||
|
||||
at::cuda::CUDAGuard device_guard{x.get_device()};
|
||||
auto stream = at::cuda::getCurrentCUDAStream().stream();
|
||||
|
||||
fp6_pack_cuda(x, out, stream);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
at::Tensor fp6_unpack(at::Tensor &x, int64_t original_n) {
|
||||
TORCH_CHECK(x.dtype() == torch::kUInt8, "Input tensor must be uint8");
|
||||
TORCH_CHECK(x.is_cuda(), "Input tensor must be on CUDA");
|
||||
TORCH_CHECK(x.is_contiguous(), "Input tensor must be contiguous");
|
||||
TORCH_CHECK(x.dim() == 2, "Input tensor must be 2D [m, n_packed]");
|
||||
TORCH_CHECK(original_n % 8 == 0, "original_n must be divisible by 8, got ", original_n);
|
||||
|
||||
int64_t m = x.size(0);
|
||||
int64_t n_packed = x.size(1);
|
||||
|
||||
TORCH_CHECK(n_packed == original_n * 3 / 4,
|
||||
"Packed size mismatch: expected ", original_n * 3 / 4, " got ", n_packed);
|
||||
|
||||
auto options = torch::TensorOptions()
|
||||
.dtype(torch::kUInt8)
|
||||
.device(x.device());
|
||||
|
||||
at::Tensor out = torch::empty({m, original_n}, options);
|
||||
|
||||
at::cuda::CUDAGuard device_guard{x.get_device()};
|
||||
auto stream = at::cuda::getCurrentCUDAStream().stream();
|
||||
|
||||
fp6_unpack_cuda(x, out, stream);
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
#include <c10/cuda/CUDAException.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda.h>
|
||||
|
||||
#include <ATen/ATen.h>
|
||||
#include <torch/types.h>
|
||||
|
||||
// Device function to pack 8-bit to 6-bit
|
||||
// 8-bit layout: s e_1 e_2 e_3 m_1 m_2 m_3 m_4 (bits 7-0)
|
||||
// 6-bit layout: s e_3 m_1 m_2 m_3 m_4 (bits 5-0)
|
||||
// Drop e_1 (bit 6) and e_2 (bit 5)
|
||||
__device__ __forceinline__ uint8_t pack_8bit_to_6bit(uint8_t input) {
|
||||
// Extract the sign bit (bit 7)
|
||||
uint8_t sign = (input >> 7) & 0x1;
|
||||
|
||||
// Extract e_3 (bit 4)
|
||||
uint8_t e_3 = (input >> 4) & 0x1;
|
||||
|
||||
// Extract mantissa bits (bits 3-0)
|
||||
uint8_t mantissa = input & 0x0F;
|
||||
|
||||
// Pack into 6-bit format: s e_3 m_1 m_2 m_3 m_4
|
||||
uint8_t result = (sign << 5) | (e_3 << 4) | mantissa;
|
||||
|
||||
return result & 0x3F; // Mask to 6 bits
|
||||
}
|
||||
|
||||
// Device function to pack 4 x 6-bit values into 3 bytes
|
||||
__device__ __forceinline__ void pack_4x6bit_to_3bytes(const uint8_t* input_6bit, uint8_t* output_3bytes) {
|
||||
uint8_t v0 = input_6bit[0] & 0x3F;
|
||||
uint8_t v1 = input_6bit[1] & 0x3F;
|
||||
uint8_t v2 = input_6bit[2] & 0x3F;
|
||||
uint8_t v3 = input_6bit[3] & 0x3F;
|
||||
|
||||
// Pack: [v0: 6 bits][v1: 6 bits][v2: 6 bits][v3: 6 bits] = 24 bits = 3 bytes
|
||||
output_3bytes[0] = (v0 << 2) | (v1 >> 4);
|
||||
output_3bytes[1] = (v1 << 4) | (v2 >> 2);
|
||||
output_3bytes[2] = (v2 << 6) | v3;
|
||||
}
|
||||
|
||||
// CUDA kernel for packing 2D tensor
|
||||
// Input: [m, n] uint8 tensor
|
||||
// Output: [m, n*3/4] uint8 tensor
|
||||
__global__ void fp6_pack_kernel(
|
||||
const uint8_t* __restrict__ input,
|
||||
uint8_t* __restrict__ output,
|
||||
int m,
|
||||
int n,
|
||||
int n_packed
|
||||
) {
|
||||
// Each thread processes one row and 4 elements at a time
|
||||
int row = blockIdx.x;
|
||||
int col_group = blockIdx.y * blockDim.x + threadIdx.x;
|
||||
|
||||
if (row >= m) return;
|
||||
|
||||
// Calculate input and output positions
|
||||
int input_col = col_group * 4;
|
||||
if (input_col >= n) return;
|
||||
|
||||
int output_col = col_group * 3;
|
||||
|
||||
const uint8_t* input_row = input + row * n;
|
||||
uint8_t* output_row = output + row * n_packed;
|
||||
|
||||
uint8_t temp_6bit[4];
|
||||
|
||||
// Pack 4 elements
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (input_col + i < n) {
|
||||
temp_6bit[i] = pack_8bit_to_6bit(input_row[input_col + i]);
|
||||
} else {
|
||||
temp_6bit[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Write 3 bytes to output
|
||||
uint8_t temp_3bytes[3];
|
||||
pack_4x6bit_to_3bytes(temp_6bit, temp_3bytes);
|
||||
|
||||
if (output_col < n_packed) output_row[output_col] = temp_3bytes[0];
|
||||
if (output_col + 1 < n_packed) output_row[output_col + 1] = temp_3bytes[1];
|
||||
if (output_col + 2 < n_packed) output_row[output_col + 2] = temp_3bytes[2];
|
||||
}
|
||||
|
||||
// Device function to unpack 6-bit to 8-bit
|
||||
__device__ __forceinline__ uint8_t unpack_6bit_to_8bit(uint8_t input) {
|
||||
input = input & 0x3F; // Ensure only 6 bits
|
||||
|
||||
uint8_t sign = (input >> 5) & 0x1;
|
||||
uint8_t e_3 = (input >> 4) & 0x1;
|
||||
uint8_t mantissa = input & 0x0F;
|
||||
|
||||
// Reconstruct 8-bit with e_1 and e_2 set to 0
|
||||
uint8_t result = (sign << 7) | (e_3 << 4) | mantissa;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Device function to unpack 3 bytes into 4 x 6-bit values
|
||||
__device__ __forceinline__ void unpack_3bytes_to_4x6bit(const uint8_t* input_3bytes, uint8_t* output_6bit) {
|
||||
output_6bit[0] = (input_3bytes[0] >> 2) & 0x3F;
|
||||
output_6bit[1] = ((input_3bytes[0] << 4) | (input_3bytes[1] >> 4)) & 0x3F;
|
||||
output_6bit[2] = ((input_3bytes[1] << 2) | (input_3bytes[2] >> 6)) & 0x3F;
|
||||
output_6bit[3] = input_3bytes[2] & 0x3F;
|
||||
}
|
||||
|
||||
// CUDA kernel for unpacking 2D tensor
|
||||
// Input: [m, n_packed] uint8 tensor
|
||||
// Output: [m, n] uint8 tensor
|
||||
__global__ void fp6_unpack_kernel(
|
||||
const uint8_t* __restrict__ input,
|
||||
uint8_t* __restrict__ output,
|
||||
int m,
|
||||
int n_packed,
|
||||
int n
|
||||
) {
|
||||
// Each thread processes one row and 4 elements at a time
|
||||
int row = blockIdx.x;
|
||||
int col_group = blockIdx.y * blockDim.x + threadIdx.x;
|
||||
|
||||
if (row >= m) return;
|
||||
|
||||
// Calculate input and output positions
|
||||
int input_col = col_group * 3;
|
||||
if (input_col >= n_packed) return;
|
||||
|
||||
int output_col = col_group * 4;
|
||||
|
||||
const uint8_t* input_row = input + row * n_packed;
|
||||
uint8_t* output_row = output + row * n;
|
||||
|
||||
// Read 3 bytes
|
||||
uint8_t temp_3bytes[3];
|
||||
temp_3bytes[0] = (input_col < n_packed) ? input_row[input_col] : 0;
|
||||
temp_3bytes[1] = (input_col + 1 < n_packed) ? input_row[input_col + 1] : 0;
|
||||
temp_3bytes[2] = (input_col + 2 < n_packed) ? input_row[input_col + 2] : 0;
|
||||
|
||||
// Unpack to 4 x 6-bit values
|
||||
uint8_t temp_6bit[4];
|
||||
unpack_3bytes_to_4x6bit(temp_3bytes, temp_6bit);
|
||||
|
||||
// Convert to 8-bit and write
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (output_col + i < n) {
|
||||
output_row[output_col + i] = unpack_6bit_to_8bit(temp_6bit[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Host function to launch pack kernel
|
||||
void fp6_pack_cuda(
|
||||
at::Tensor& x,
|
||||
at::Tensor& out,
|
||||
cudaStream_t stream
|
||||
) {
|
||||
int m = x.size(0);
|
||||
int n = x.size(1);
|
||||
int n_packed = out.size(1);
|
||||
|
||||
const uint8_t* input_ptr = (uint8_t*)x.data_ptr();
|
||||
uint8_t* output_ptr = (uint8_t*)out.data_ptr();
|
||||
|
||||
// Each thread handles 4 input elements -> 3 output bytes
|
||||
int num_groups = (n + 3) / 4;
|
||||
|
||||
int threads = 256;
|
||||
dim3 blocks(m, (num_groups + threads - 1) / threads);
|
||||
|
||||
fp6_pack_kernel<<<blocks, threads, 0, stream>>>(
|
||||
input_ptr,
|
||||
output_ptr,
|
||||
m,
|
||||
n,
|
||||
n_packed
|
||||
);
|
||||
|
||||
C10_CUDA_KERNEL_LAUNCH_CHECK();
|
||||
}
|
||||
|
||||
// Host function to launch unpack kernel
|
||||
void fp6_unpack_cuda(
|
||||
at::Tensor& x,
|
||||
at::Tensor& out,
|
||||
cudaStream_t stream
|
||||
) {
|
||||
int m = x.size(0);
|
||||
int n_packed = x.size(1);
|
||||
int n = out.size(1);
|
||||
|
||||
const uint8_t* input_ptr = (uint8_t*)x.data_ptr();
|
||||
uint8_t* output_ptr = (uint8_t*)out.data_ptr();
|
||||
|
||||
// Each thread handles 3 input bytes -> 4 output elements
|
||||
int num_groups = (n + 3) / 4;
|
||||
|
||||
int threads = 256;
|
||||
dim3 blocks(m, (num_groups + threads - 1) / threads);
|
||||
|
||||
fp6_unpack_kernel<<<blocks, threads, 0, stream>>>(
|
||||
input_ptr,
|
||||
output_ptr,
|
||||
m,
|
||||
n_packed,
|
||||
n
|
||||
);
|
||||
|
||||
C10_CUDA_KERNEL_LAUNCH_CHECK();
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2023, Tri Dao.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct HadamardParamsBase {
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
};
|
||||
|
||||
struct UnifiedHadamardParamsBase{
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
int batch_fma_change;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
index_t fma_batch_stride;
|
||||
index_t cos_freq_batch_stride;
|
||||
index_t sin_freq_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
void *__restrict__ out_scales_ptr;
|
||||
|
||||
void *__restrict__ y_scale_ptr;
|
||||
void *__restrict__ z_shift_ptr;
|
||||
|
||||
void *__restrict__ weights_ptr;
|
||||
|
||||
void *__restrict__ cos_freq_ptr;
|
||||
void *__restrict__ sin_freq_ptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct DequantHadamardParamsBase {
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ scales_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
};
|
||||
|
||||
|
||||
struct QuantHadamardParamsBase {
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
void *__restrict__ out_scales_ptr;
|
||||
};
|
||||
|
||||
struct NormFMAHadamardParamsBase {
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
int seqlen;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
index_t fma_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
void *__restrict__ y_scale_ptr;
|
||||
void *__restrict__ z_shift_ptr;
|
||||
void *__restrict__ weights_ptr;
|
||||
};
|
||||
|
||||
|
||||
struct NormRopeHadamardParamsBase {
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
index_t cos_freq_batch_stride;
|
||||
index_t sin_freq_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
void *__restrict__ cos_freq_ptr;
|
||||
void *__restrict__ sin_freq_ptr;
|
||||
void *__restrict__ weights_ptr;
|
||||
};
|
||||
|
||||
|
||||
struct NormHadamardParamsBase {
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
void *__restrict__ weights_ptr;
|
||||
};
|
||||
|
||||
|
||||
struct RopeHadamardParamsBase {
|
||||
using index_t = int64_t;
|
||||
|
||||
int batch, dim, log_N;
|
||||
|
||||
index_t x_batch_stride;
|
||||
index_t out_batch_stride;
|
||||
index_t cos_freq_batch_stride;
|
||||
index_t sin_freq_batch_stride;
|
||||
|
||||
float scale;
|
||||
|
||||
// Common data pointers.
|
||||
void *__restrict__ x_ptr;
|
||||
void *__restrict__ out_ptr;
|
||||
void *__restrict__ cos_freq_ptr;
|
||||
void *__restrict__ sin_freq_ptr;
|
||||
};
|
||||
@@ -0,0 +1,319 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2023, Tri Dao.
|
||||
******************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cuda_bf16.h>
|
||||
#include <cuda_fp16.h>
|
||||
|
||||
#define FULL_MASK 0xffffffff
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename TYPE> struct QuantMax {};
|
||||
template<> struct QuantMax<int8_t> { static constexpr float value = 127.0; };
|
||||
template<> struct QuantMax<at::Float8_e4m3fn> { static constexpr float value = 256.0; };
|
||||
|
||||
struct uint8 {
|
||||
uint4 u;
|
||||
uint4 v;
|
||||
};
|
||||
|
||||
template<int BYTES> struct BytesToType {};
|
||||
|
||||
template<>
|
||||
struct BytesToType<32> {
|
||||
using Type = uint8;
|
||||
static_assert(sizeof(Type) == 32);
|
||||
};
|
||||
|
||||
template<> struct BytesToType<16> {
|
||||
using Type = uint4;
|
||||
static_assert(sizeof(Type) == 16);
|
||||
};
|
||||
|
||||
template<> struct BytesToType<8> {
|
||||
using Type = uint64_t;
|
||||
static_assert(sizeof(Type) == 8);
|
||||
};
|
||||
|
||||
template<> struct BytesToType<4> {
|
||||
using Type = uint32_t;
|
||||
static_assert(sizeof(Type) == 4);
|
||||
};
|
||||
|
||||
template<> struct BytesToType<2> {
|
||||
using Type = uint16_t;
|
||||
static_assert(sizeof(Type) == 2);
|
||||
};
|
||||
|
||||
template<> struct BytesToType<1> {
|
||||
using Type = uint8_t;
|
||||
static_assert(sizeof(Type) == 1);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
struct SumOp {
|
||||
__device__ inline T operator()(T const & x, T const & y) { return x + y; }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct MaxOp {
|
||||
__device__ inline T operator()(T const & x, T const & y) { return max(x, y); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MaxOp<float> {
|
||||
// This is slightly faster
|
||||
__device__ inline float operator()(float const &x, float const &y) { return max(x, y); }
|
||||
};
|
||||
|
||||
|
||||
template<int THREADS>
|
||||
struct Allreduce {
|
||||
static_assert(THREADS == 32 || THREADS == 16 || THREADS == 8 || THREADS == 4);
|
||||
template<typename T, typename Operator>
|
||||
static __device__ inline T run(T x, Operator &op) {
|
||||
constexpr int OFFSET = THREADS / 2;
|
||||
x = op(x, __shfl_xor_sync(uint32_t(-1), x, OFFSET));
|
||||
return Allreduce<OFFSET>::run(x, op);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Allreduce<2> {
|
||||
template<typename T, typename Operator>
|
||||
static __device__ inline T run(T x, Operator &op) {
|
||||
x = op(x, __shfl_xor_sync(uint32_t(-1), x, 1));
|
||||
return x;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// https://stackoverflow.com/questions/35311711/whats-the-right-way-to-compute-integral-base-2-logarithms-at-compile-time
|
||||
constexpr int cilog2(int val) { return val > 0 ? 1 + cilog2(val >> 1) : -1; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<int kLogN, int kNChunks>
|
||||
__device__ __forceinline__ void hadamard_mult_thread(float x[kNChunks][1 << kLogN]) {
|
||||
constexpr int N = 1 << kLogN;
|
||||
#pragma unroll
|
||||
for (int i = 0; i < kLogN; ++i) {
|
||||
const int stride = 1 << i;
|
||||
#pragma unroll
|
||||
for (int j = 0; j < N / 2; ++j) {
|
||||
const int lo = j & (stride - 1);
|
||||
const int idx = (j - lo) * 2 + lo;
|
||||
#pragma unroll
|
||||
for (int c = 0; c < kNChunks; ++c) {
|
||||
const float a = x[c][idx];
|
||||
const float b = x[c][idx + stride];
|
||||
x[c][idx] = a + b;
|
||||
x[c][idx + stride] = a - b;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int kLogWarpSize, int kStepStart, int kNChunks, int kNItems>
|
||||
__device__ __forceinline__ void hadamard_mult_warp(float x[kNChunks][kNItems]) {
|
||||
constexpr int N = 1 << kLogWarpSize;
|
||||
int lane_id = threadIdx.x % N;
|
||||
#pragma unroll
|
||||
for (int step = kStepStart; step < kLogWarpSize; ++step) {
|
||||
const int lane_mask = 1 << step;
|
||||
const float sign = (lane_id & lane_mask) ? -1.f : 1.f;
|
||||
#pragma unroll
|
||||
for (int c = 0; c < kNChunks; ++c) {
|
||||
#pragma unroll
|
||||
for (int i = 0; i < kNItems; ++i) {
|
||||
float x_val_other = __shfl_xor_sync(FULL_MASK, x[c][i], lane_mask);
|
||||
x[c][i] = sign * x[c][i] + x_val_other;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <int kNChunks, int kNElts, typename input_t>
|
||||
inline __device__ void load_input(input_t *x, float x_vals[kNChunks][kNElts], int dim) {
|
||||
using vec_t = typename BytesToType<sizeof(input_t) * kNElts>::Type;
|
||||
input_t x_vals_load[kNChunks][kNElts] = {0};
|
||||
#pragma unroll
|
||||
for (int c = 0; c < kNChunks; ++c) {
|
||||
if ((c * blockDim.x + threadIdx.x) * kNElts < dim) {
|
||||
reinterpret_cast<vec_t*>(x_vals_load)[c] = reinterpret_cast<const vec_t*>(x)[c * blockDim.x + threadIdx.x];
|
||||
}
|
||||
}
|
||||
#pragma unroll
|
||||
for (int c = 0; c < kNChunks; ++c) {
|
||||
#pragma unroll
|
||||
for (int i = 0; i < kNElts; ++i) { x_vals[c][i] = float(x_vals_load[c][i]); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int kNChunks, int kNElts, typename output_t, bool do_round>
|
||||
inline __device__ void store_output(output_t *out, float out_vals[kNChunks][kNElts], int dim, float scale=1.f) {
|
||||
using vec_t = typename BytesToType<sizeof(output_t) * kNElts>::Type;
|
||||
output_t out_vals_store[kNChunks][kNElts];
|
||||
#pragma unroll
|
||||
for (int c = 0; c < kNChunks; ++c) {
|
||||
#pragma unroll
|
||||
for (int i = 0; i < kNElts; ++i) {
|
||||
if constexpr (do_round){
|
||||
out_vals_store[c][i] = round(out_vals[c][i] * scale);
|
||||
} else {
|
||||
out_vals_store[c][i] = out_vals[c][i] * scale;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#pragma unroll
|
||||
for (int c = 0; c < kNChunks; ++c) {
|
||||
if ((c * blockDim.x + threadIdx.x) * kNElts < dim) {
|
||||
reinterpret_cast<vec_t*>(out)[c * blockDim.x + threadIdx.x] = reinterpret_cast<const vec_t*>(out_vals_store)[c];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Pre=true means the exchange before the hadamard_mult_warp, Pre=false means after.
|
||||
template <int kNChunks, int kChunksPerExchange, int kNElts, int kWarpSize, int kNWarps, bool Pre, typename vec_t>
|
||||
inline __device__ void exchange_smem_pre(float x_vals[kNChunks][kNElts], vec_t *smem) {
|
||||
constexpr int kNThreads = kWarpSize * kNWarps;
|
||||
constexpr int kNExchangePerVec = kNElts / (sizeof(vec_t) / sizeof(float));
|
||||
const int warp_id = threadIdx.x / kWarpSize;
|
||||
const int lane_id = threadIdx.x % kWarpSize;
|
||||
const int row_t = threadIdx.x % kNWarps;
|
||||
const int col_t = threadIdx.x / kNWarps;
|
||||
// We use the XOR swizzle trick (new_col = col ^ row) to avoid / reduce smem bank conflicts.
|
||||
#pragma unroll
|
||||
for (int c0 = 0; c0 < kNChunks / kChunksPerExchange; ++c0) {
|
||||
__syncthreads();
|
||||
#pragma unroll
|
||||
for (int c1 = 0; c1 < kChunksPerExchange; ++c1) {
|
||||
#pragma unroll
|
||||
for (int r = 0; r < kNExchangePerVec; ++r) {
|
||||
smem[(c1 * kNExchangePerVec + r) * kNThreads + (Pre ? warp_id * kWarpSize + lane_id ^ warp_id : row_t * kWarpSize + col_t ^ row_t)] = reinterpret_cast<vec_t*>(x_vals[c0 * kChunksPerExchange + c1])[r];
|
||||
}
|
||||
}
|
||||
__syncthreads();
|
||||
#pragma unroll
|
||||
for (int c1 = 0; c1 < kChunksPerExchange; ++c1) {
|
||||
#pragma unroll
|
||||
for (int r = 0; r < kNExchangePerVec; ++r) {
|
||||
reinterpret_cast<vec_t*>(x_vals[c0 * kChunksPerExchange + c1])[r] = smem[(c1 * kNExchangePerVec + r) * kNThreads + (Pre ? row_t * kWarpSize + col_t ^ row_t : warp_id * kWarpSize + lane_id ^ warp_id)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline __device__ float gelu_approximate(float x){
|
||||
constexpr float sqrthalfpi2 = 0.7978845608028653558798921198687637369517172623298693153318516593f;
|
||||
constexpr float factor = 0.044715f;
|
||||
return 0.5f*x*(1.0f + tanhf(sqrthalfpi2*(x + factor*x*x*x)));
|
||||
}
|
||||
|
||||
template <int kNChunks, int kNElts>
|
||||
inline __device__ void fused_gelu(float x_vals[kNChunks][kNElts]){
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i++)
|
||||
{
|
||||
x_vals[c][i] = gelu_approximate(x_vals[c][i]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <int kNChunks, int kNElts, int kNWarps, bool norm_affine>
|
||||
inline __device__ void fused_rms_norm(float x_vals[kNChunks][kNElts], float weights_vals[kNChunks][kNElts], float* smem_sum, float dim){
|
||||
float thread_squared_sum = 0.0f;
|
||||
const int warp_id = threadIdx.x / 32;
|
||||
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i++)
|
||||
{
|
||||
thread_squared_sum += x_vals[c][i] * x_vals[c][i];
|
||||
}
|
||||
|
||||
}
|
||||
SumOp<float> sum_op;
|
||||
float warp_sum = Allreduce<32>::run(thread_squared_sum, sum_op);
|
||||
|
||||
if(threadIdx.x % 32 == 0){
|
||||
smem_sum[warp_id] = warp_sum;
|
||||
}
|
||||
__syncthreads();
|
||||
float norm = 0.0f;
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNWarps; i++)
|
||||
{
|
||||
norm += smem_sum[i];
|
||||
}
|
||||
|
||||
norm *= 1.0f/dim;
|
||||
norm = rsqrtf(norm + 0.0000001f);
|
||||
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i++)
|
||||
{
|
||||
if constexpr (norm_affine){
|
||||
x_vals[c][i] *= (norm * weights_vals[c][i]);
|
||||
} else {
|
||||
x_vals[c][i] *= norm;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int kNChunks, int kNElts>
|
||||
inline __device__ void fused_rope(float x_vals[kNChunks][kNElts], float sin_freqs_vals[kNChunks][kNElts], float cos_freqs_vals[kNChunks][kNElts]){
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i+=2)
|
||||
{
|
||||
float x_1 = x_vals[c][i];
|
||||
float x_2 = x_vals[c][i+1];
|
||||
x_vals[c][i] = -x_2*sin_freqs_vals[c][i] + x_1*cos_freqs_vals[c][i];
|
||||
x_vals[c][i+1] = x_1*sin_freqs_vals[c][i+1] + x_2*cos_freqs_vals[c][i+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int kNChunks, int kNElts, bool add_one_scale>
|
||||
inline __device__ void fused_multiply_add(float x_vals[kNChunks][kNElts], float y_scale_vals[kNChunks][kNElts], float z_shift_vals[kNChunks][kNElts]) {
|
||||
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i++)
|
||||
{
|
||||
if constexpr (add_one_scale){
|
||||
x_vals[c][i] = x_vals[c][i] * (1.0f + y_scale_vals[c][i]) + z_shift_vals[c][i];
|
||||
} else {
|
||||
x_vals[c][i] = x_vals[c][i] * y_scale_vals[c][i] + z_shift_vals[c][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2023, Tri Dao.
|
||||
******************************************************************************/
|
||||
|
||||
// This file is auto-generated. See "code_gen.py"
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
__device__ __forceinline__ void hadamard_mult_thread_12(float x[12]) {
|
||||
float out[12];
|
||||
out[0] = + x[0] - x[1] + x[2] + x[3] + x[4] + x[5] + x[6] + x[7] + x[8] + x[9] + x[10] + x[11];
|
||||
out[1] = - x[0] - x[1] + x[2] - x[3] + x[4] - x[5] + x[6] - x[7] + x[8] - x[9] + x[10] - x[11];
|
||||
out[2] = + x[0] + x[1] + x[2] - x[3] + x[4] + x[5] - x[6] - x[7] - x[8] - x[9] + x[10] + x[11];
|
||||
out[3] = + x[0] - x[1] - x[2] - x[3] + x[4] - x[5] - x[6] + x[7] - x[8] + x[9] + x[10] - x[11];
|
||||
out[4] = + x[0] + x[1] + x[2] + x[3] + x[4] - x[5] + x[6] + x[7] - x[8] - x[9] - x[10] - x[11];
|
||||
out[5] = + x[0] - x[1] + x[2] - x[3] - x[4] - x[5] + x[6] - x[7] - x[8] + x[9] - x[10] + x[11];
|
||||
out[6] = + x[0] + x[1] - x[2] - x[3] + x[4] + x[5] + x[6] - x[7] + x[8] + x[9] - x[10] - x[11];
|
||||
out[7] = + x[0] - x[1] - x[2] + x[3] + x[4] - x[5] - x[6] - x[7] + x[8] - x[9] - x[10] + x[11];
|
||||
out[8] = + x[0] + x[1] - x[2] - x[3] - x[4] - x[5] + x[6] + x[7] + x[8] - x[9] + x[10] + x[11];
|
||||
out[9] = + x[0] - x[1] - x[2] + x[3] - x[4] + x[5] + x[6] - x[7] - x[8] - x[9] + x[10] - x[11];
|
||||
out[10] = + x[0] + x[1] + x[2] + x[3] - x[4] - x[5] - x[6] - x[7] + x[8] + x[9] + x[10] - x[11];
|
||||
out[11] = + x[0] - x[1] + x[2] - x[3] - x[4] + x[5] - x[6] + x[7] + x[8] - x[9] - x[10] - x[11];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 12; i++) { x[i] = out[i]; }
|
||||
}
|
||||
|
||||
|
||||
__device__ __forceinline__ void hadamard_mult_thread_20(float x[20]) {
|
||||
float out[20];
|
||||
out[0] = + x[0] - x[1] - x[2] - x[3] - x[4] + x[5] - x[6] - x[7] - x[8] - x[9] + x[10] + x[11] - x[12] - x[13] + x[14] + x[15] - x[16] + x[17] + x[18] - x[19];
|
||||
out[1] = - x[0] + x[1] - x[2] - x[3] - x[4] - x[5] + x[6] - x[7] - x[8] - x[9] + x[10] + x[11] + x[12] - x[13] - x[14] - x[15] + x[16] - x[17] + x[18] + x[19];
|
||||
out[2] = - x[0] - x[1] + x[2] - x[3] - x[4] - x[5] - x[6] + x[7] - x[8] - x[9] - x[10] + x[11] + x[12] + x[13] - x[14] + x[15] - x[16] + x[17] - x[18] + x[19];
|
||||
out[3] = - x[0] - x[1] - x[2] + x[3] - x[4] - x[5] - x[6] - x[7] + x[8] - x[9] - x[10] - x[11] + x[12] + x[13] + x[14] + x[15] + x[16] - x[17] + x[18] - x[19];
|
||||
out[4] = - x[0] - x[1] - x[2] - x[3] + x[4] - x[5] - x[6] - x[7] - x[8] + x[9] + x[10] - x[11] - x[12] + x[13] + x[14] - x[15] + x[16] + x[17] - x[18] + x[19];
|
||||
out[5] = - x[0] + x[1] + x[2] + x[3] + x[4] + x[5] - x[6] - x[7] - x[8] - x[9] - x[10] + x[11] - x[12] - x[13] + x[14] + x[15] + x[16] - x[17] - x[18] + x[19];
|
||||
out[6] = + x[0] - x[1] + x[2] + x[3] + x[4] - x[5] + x[6] - x[7] - x[8] - x[9] + x[10] - x[11] + x[12] - x[13] - x[14] + x[15] + x[16] + x[17] - x[18] - x[19];
|
||||
out[7] = + x[0] + x[1] - x[2] + x[3] + x[4] - x[5] - x[6] + x[7] - x[8] - x[9] - x[10] + x[11] - x[12] + x[13] - x[14] - x[15] + x[16] + x[17] + x[18] - x[19];
|
||||
out[8] = + x[0] + x[1] + x[2] - x[3] + x[4] - x[5] - x[6] - x[7] + x[8] - x[9] - x[10] - x[11] + x[12] - x[13] + x[14] - x[15] - x[16] + x[17] + x[18] + x[19];
|
||||
out[9] = + x[0] + x[1] + x[2] + x[3] - x[4] - x[5] - x[6] - x[7] - x[8] + x[9] + x[10] - x[11] - x[12] + x[13] - x[14] + x[15] - x[16] - x[17] + x[18] + x[19];
|
||||
out[10] = - x[0] - x[1] + x[2] + x[3] - x[4] + x[5] - x[6] + x[7] + x[8] - x[9] + x[10] - x[11] - x[12] - x[13] - x[14] - x[15] + x[16] + x[17] + x[18] + x[19];
|
||||
out[11] = - x[0] - x[1] - x[2] + x[3] + x[4] - x[5] + x[6] - x[7] + x[8] + x[9] - x[10] + x[11] - x[12] - x[13] - x[14] + x[15] - x[16] + x[17] + x[18] + x[19];
|
||||
out[12] = + x[0] - x[1] - x[2] - x[3] + x[4] + x[5] - x[6] + x[7] - x[8] + x[9] - x[10] - x[11] + x[12] - x[13] - x[14] + x[15] + x[16] - x[17] + x[18] + x[19];
|
||||
out[13] = + x[0] + x[1] - x[2] - x[3] - x[4] + x[5] + x[6] - x[7] + x[8] - x[9] - x[10] - x[11] - x[12] + x[13] - x[14] + x[15] + x[16] + x[17] - x[18] + x[19];
|
||||
out[14] = - x[0] + x[1] + x[2] - x[3] - x[4] - x[5] + x[6] + x[7] - x[8] + x[9] - x[10] - x[11] - x[12] - x[13] + x[14] + x[15] + x[16] + x[17] + x[18] - x[19];
|
||||
out[15] = - x[0] + x[1] - x[2] - x[3] + x[4] - x[5] - x[6] + x[7] + x[8] - x[9] + x[10] - x[11] - x[12] - x[13] - x[14] + x[15] - x[16] - x[17] - x[18] - x[19];
|
||||
out[16] = + x[0] - x[1] + x[2] - x[3] - x[4] - x[5] - x[6] - x[7] + x[8] + x[9] - x[10] + x[11] - x[12] - x[13] - x[14] - x[15] + x[16] - x[17] - x[18] - x[19];
|
||||
out[17] = - x[0] + x[1] - x[2] + x[3] - x[4] + x[5] - x[6] - x[7] - x[8] + x[9] - x[10] - x[11] + x[12] - x[13] - x[14] - x[15] - x[16] + x[17] - x[18] - x[19];
|
||||
out[18] = - x[0] - x[1] + x[2] - x[3] + x[4] + x[5] + x[6] - x[7] - x[8] - x[9] - x[10] - x[11] - x[12] + x[13] - x[14] - x[15] - x[16] - x[17] + x[18] - x[19];
|
||||
out[19] = + x[0] - x[1] - x[2] + x[3] - x[4] - x[5] + x[6] + x[7] - x[8] - x[9] - x[10] - x[11] - x[12] - x[13] + x[14] - x[15] - x[16] - x[17] - x[18] + x[19];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 20; i++) { x[i] = out[i]; }
|
||||
}
|
||||
|
||||
|
||||
__device__ __forceinline__ void hadamard_mult_thread_28(float x[28]) {
|
||||
float out[28];
|
||||
out[0] = + x[0] - x[1] - x[2] - x[3] - x[4] - x[5] - x[6] + x[7] + x[8] - x[9] - x[10] - x[11] - x[12] + x[13] + x[14] - x[15] + x[16] - x[17] - x[18] + x[19] - x[20] + x[21] - x[22] - x[23] + x[24] + x[25] - x[26] - x[27];
|
||||
out[1] = - x[0] + x[1] - x[2] - x[3] - x[4] - x[5] - x[6] + x[7] + x[8] + x[9] - x[10] - x[11] - x[12] - x[13] - x[14] + x[15] - x[16] + x[17] - x[18] - x[19] + x[20] - x[21] + x[22] - x[23] - x[24] + x[25] + x[26] - x[27];
|
||||
out[2] = - x[0] - x[1] + x[2] - x[3] - x[4] - x[5] - x[6] - x[7] + x[8] + x[9] + x[10] - x[11] - x[12] - x[13] + x[14] - x[15] + x[16] - x[17] + x[18] - x[19] - x[20] - x[21] - x[22] + x[23] - x[24] - x[25] + x[26] + x[27];
|
||||
out[3] = - x[0] - x[1] - x[2] + x[3] - x[4] - x[5] - x[6] - x[7] - x[8] + x[9] + x[10] + x[11] - x[12] - x[13] - x[14] + x[15] - x[16] + x[17] - x[18] + x[19] - x[20] + x[21] - x[22] - x[23] + x[24] - x[25] - x[26] + x[27];
|
||||
out[4] = - x[0] - x[1] - x[2] - x[3] + x[4] - x[5] - x[6] - x[7] - x[8] - x[9] + x[10] + x[11] + x[12] - x[13] - x[14] - x[15] + x[16] - x[17] + x[18] - x[19] + x[20] + x[21] + x[22] - x[23] - x[24] + x[25] - x[26] - x[27];
|
||||
out[5] = - x[0] - x[1] - x[2] - x[3] - x[4] + x[5] - x[6] - x[7] - x[8] - x[9] - x[10] + x[11] + x[12] + x[13] + x[14] - x[15] - x[16] + x[17] - x[18] + x[19] - x[20] - x[21] + x[22] + x[23] - x[24] - x[25] + x[26] - x[27];
|
||||
out[6] = - x[0] - x[1] - x[2] - x[3] - x[4] - x[5] + x[6] + x[7] - x[8] - x[9] - x[10] - x[11] + x[12] + x[13] - x[14] + x[15] - x[16] - x[17] + x[18] - x[19] + x[20] - x[21] - x[22] + x[23] + x[24] - x[25] - x[26] + x[27];
|
||||
out[7] = - x[0] - x[1] + x[2] + x[3] + x[4] + x[5] - x[6] + x[7] - x[8] - x[9] - x[10] - x[11] - x[12] - x[13] - x[14] + x[15] + x[16] - x[17] - x[18] + x[19] + x[20] + x[21] - x[22] + x[23] - x[24] - x[25] + x[26] - x[27];
|
||||
out[8] = - x[0] - x[1] - x[2] + x[3] + x[4] + x[5] + x[6] - x[7] + x[8] - x[9] - x[10] - x[11] - x[12] - x[13] + x[14] - x[15] + x[16] + x[17] - x[18] - x[19] + x[20] - x[21] + x[22] - x[23] + x[24] - x[25] - x[26] + x[27];
|
||||
out[9] = + x[0] - x[1] - x[2] - x[3] + x[4] + x[5] + x[6] - x[7] - x[8] + x[9] - x[10] - x[11] - x[12] - x[13] + x[14] + x[15] - x[16] + x[17] + x[18] - x[19] - x[20] + x[21] - x[22] + x[23] - x[24] + x[25] - x[26] - x[27];
|
||||
out[10] = + x[0] + x[1] - x[2] - x[3] - x[4] + x[5] + x[6] - x[7] - x[8] - x[9] + x[10] - x[11] - x[12] - x[13] - x[14] + x[15] + x[16] - x[17] + x[18] + x[19] - x[20] - x[21] + x[22] - x[23] + x[24] - x[25] + x[26] - x[27];
|
||||
out[11] = + x[0] + x[1] + x[2] - x[3] - x[4] - x[5] + x[6] - x[7] - x[8] - x[9] - x[10] + x[11] - x[12] - x[13] - x[14] - x[15] + x[16] + x[17] - x[18] + x[19] + x[20] - x[21] - x[22] + x[23] - x[24] + x[25] - x[26] + x[27];
|
||||
out[12] = + x[0] + x[1] + x[2] + x[3] - x[4] - x[5] - x[6] - x[7] - x[8] - x[9] - x[10] - x[11] + x[12] - x[13] + x[14] - x[15] - x[16] + x[17] + x[18] - x[19] + x[20] + x[21] - x[22] - x[23] + x[24] - x[25] + x[26] - x[27];
|
||||
out[13] = - x[0] + x[1] + x[2] + x[3] + x[4] - x[5] - x[6] - x[7] - x[8] - x[9] - x[10] - x[11] - x[12] + x[13] + x[14] + x[15] - x[16] - x[17] + x[18] + x[19] - x[20] - x[21] + x[22] - x[23] - x[24] + x[25] - x[26] + x[27];
|
||||
out[14] = - x[0] + x[1] - x[2] + x[3] + x[4] - x[5] + x[6] + x[7] - x[8] - x[9] + x[10] + x[11] - x[12] - x[13] + x[14] - x[15] - x[16] - x[17] - x[18] - x[19] - x[20] - x[21] - x[22] + x[23] + x[24] + x[25] + x[26] - x[27];
|
||||
out[15] = + x[0] - x[1] + x[2] - x[3] + x[4] + x[5] - x[6] - x[7] + x[8] - x[9] - x[10] + x[11] + x[12] - x[13] - x[14] + x[15] - x[16] - x[17] - x[18] - x[19] - x[20] - x[21] - x[22] - x[23] + x[24] + x[25] + x[26] + x[27];
|
||||
out[16] = - x[0] + x[1] - x[2] + x[3] - x[4] + x[5] + x[6] - x[7] - x[8] + x[9] - x[10] - x[11] + x[12] + x[13] - x[14] - x[15] + x[16] - x[17] - x[18] - x[19] - x[20] + x[21] - x[22] - x[23] - x[24] + x[25] + x[26] + x[27];
|
||||
out[17] = + x[0] - x[1] + x[2] - x[3] + x[4] - x[5] + x[6] + x[7] - x[8] - x[9] + x[10] - x[11] - x[12] + x[13] - x[14] - x[15] - x[16] + x[17] - x[18] - x[19] - x[20] + x[21] + x[22] - x[23] - x[24] - x[25] + x[26] + x[27];
|
||||
out[18] = + x[0] + x[1] - x[2] + x[3] - x[4] + x[5] - x[6] + x[7] + x[8] - x[9] - x[10] + x[11] - x[12] - x[13] - x[14] - x[15] - x[16] - x[17] + x[18] - x[19] - x[20] + x[21] + x[22] + x[23] - x[24] - x[25] - x[26] + x[27];
|
||||
out[19] = - x[0] + x[1] + x[2] - x[3] + x[4] - x[5] + x[6] - x[7] + x[8] + x[9] - x[10] - x[11] + x[12] - x[13] - x[14] - x[15] - x[16] - x[17] - x[18] + x[19] - x[20] + x[21] + x[22] + x[23] + x[24] - x[25] - x[26] - x[27];
|
||||
out[20] = + x[0] - x[1] + x[2] + x[3] - x[4] + x[5] - x[6] - x[7] - x[8] + x[9] + x[10] - x[11] - x[12] + x[13] - x[14] - x[15] - x[16] - x[17] - x[18] - x[19] + x[20] - x[21] + x[22] + x[23] + x[24] + x[25] - x[26] - x[27];
|
||||
out[21] = - x[0] + x[1] + x[2] - x[3] - x[4] + x[5] + x[6] - x[7] + x[8] - x[9] + x[10] + x[11] - x[12] + x[13] + x[14] + x[15] - x[16] - x[17] - x[18] - x[19] + x[20] + x[21] - x[22] - x[23] - x[24] - x[25] - x[26] - x[27];
|
||||
out[22] = + x[0] - x[1] + x[2] + x[3] - x[4] - x[5] + x[6] + x[7] - x[8] + x[9] - x[10] + x[11] + x[12] - x[13] + x[14] + x[15] + x[16] - x[17] - x[18] - x[19] - x[20] - x[21] + x[22] - x[23] - x[24] - x[25] - x[26] - x[27];
|
||||
out[23] = + x[0] + x[1] - x[2] + x[3] + x[4] - x[5] - x[6] - x[7] + x[8] - x[9] + x[10] - x[11] + x[12] + x[13] - x[14] + x[15] + x[16] + x[17] - x[18] - x[19] - x[20] - x[21] - x[22] + x[23] - x[24] - x[25] - x[26] - x[27];
|
||||
out[24] = - x[0] + x[1] + x[2] - x[3] + x[4] + x[5] - x[6] + x[7] - x[8] + x[9] - x[10] + x[11] - x[12] + x[13] - x[14] - x[15] + x[16] + x[17] + x[18] - x[19] - x[20] - x[21] - x[22] - x[23] + x[24] - x[25] - x[26] - x[27];
|
||||
out[25] = - x[0] - x[1] + x[2] + x[3] - x[4] + x[5] + x[6] + x[7] + x[8] - x[9] + x[10] - x[11] + x[12] - x[13] - x[14] - x[15] - x[16] + x[17] + x[18] + x[19] - x[20] - x[21] - x[22] - x[23] - x[24] + x[25] - x[26] - x[27];
|
||||
out[26] = + x[0] - x[1] - x[2] + x[3] + x[4] - x[5] + x[6] - x[7] + x[8] + x[9] - x[10] + x[11] - x[12] + x[13] - x[14] - x[15] - x[16] - x[17] + x[18] + x[19] + x[20] - x[21] - x[22] - x[23] - x[24] - x[25] + x[26] - x[27];
|
||||
out[27] = + x[0] + x[1] - x[2] - x[3] + x[4] + x[5] - x[6] + x[7] - x[8] + x[9] + x[10] - x[11] + x[12] - x[13] + x[14] - x[15] - x[16] - x[17] - x[18] + x[19] + x[20] - x[21] - x[22] - x[23] - x[24] - x[25] - x[26] + x[27];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 28; i++) { x[i] = out[i]; }
|
||||
}
|
||||
|
||||
|
||||
__device__ __forceinline__ void hadamard_mult_thread_40(float x[40]) {
|
||||
float out[40];
|
||||
out[0] = + x[0] - x[1] - x[2] - x[3] - x[4] - x[5] - x[6] - x[7] - x[8] - x[9] - x[10] - x[11] - x[12] - x[13] - x[14] - x[15] - x[16] - x[17] - x[18] - x[19] + x[20] - x[21] - x[22] - x[23] - x[24] - x[25] - x[26] - x[27] - x[28] - x[29] - x[30] - x[31] - x[32] - x[33] - x[34] - x[35] - x[36] - x[37] - x[38] - x[39];
|
||||
out[1] = + x[0] + x[1] - x[2] + x[3] + x[4] - x[5] - x[6] - x[7] - x[8] + x[9] - x[10] + x[11] - x[12] + x[13] + x[14] + x[15] + x[16] - x[17] - x[18] + x[19] + x[20] + x[21] - x[22] + x[23] + x[24] - x[25] - x[26] - x[27] - x[28] + x[29] - x[30] + x[31] - x[32] + x[33] + x[34] + x[35] + x[36] - x[37] - x[38] + x[39];
|
||||
out[2] = + x[0] + x[1] + x[2] - x[3] + x[4] + x[5] - x[6] - x[7] - x[8] - x[9] + x[10] - x[11] + x[12] - x[13] + x[14] + x[15] + x[16] + x[17] - x[18] - x[19] + x[20] + x[21] + x[22] - x[23] + x[24] + x[25] - x[26] - x[27] - x[28] - x[29] + x[30] - x[31] + x[32] - x[33] + x[34] + x[35] + x[36] + x[37] - x[38] - x[39];
|
||||
out[3] = + x[0] - x[1] + x[2] + x[3] - x[4] + x[5] + x[6] - x[7] - x[8] - x[9] - x[10] + x[11] - x[12] + x[13] - x[14] + x[15] + x[16] + x[17] + x[18] - x[19] + x[20] - x[21] + x[22] + x[23] - x[24] + x[25] + x[26] - x[27] - x[28] - x[29] - x[30] + x[31] - x[32] + x[33] - x[34] + x[35] + x[36] + x[37] + x[38] - x[39];
|
||||
out[4] = + x[0] - x[1] - x[2] + x[3] + x[4] - x[5] + x[6] + x[7] - x[8] - x[9] - x[10] - x[11] + x[12] - x[13] + x[14] - x[15] + x[16] + x[17] + x[18] + x[19] + x[20] - x[21] - x[22] + x[23] + x[24] - x[25] + x[26] + x[27] - x[28] - x[29] - x[30] - x[31] + x[32] - x[33] + x[34] - x[35] + x[36] + x[37] + x[38] + x[39];
|
||||
out[5] = + x[0] + x[1] - x[2] - x[3] + x[4] + x[5] - x[6] + x[7] + x[8] - x[9] - x[10] - x[11] - x[12] + x[13] - x[14] + x[15] - x[16] + x[17] + x[18] + x[19] + x[20] + x[21] - x[22] - x[23] + x[24] + x[25] - x[26] + x[27] + x[28] - x[29] - x[30] - x[31] - x[32] + x[33] - x[34] + x[35] - x[36] + x[37] + x[38] + x[39];
|
||||
out[6] = + x[0] + x[1] + x[2] - x[3] - x[4] + x[5] + x[6] - x[7] + x[8] + x[9] - x[10] - x[11] - x[12] - x[13] + x[14] - x[15] + x[16] - x[17] + x[18] + x[19] + x[20] + x[21] + x[22] - x[23] - x[24] + x[25] + x[26] - x[27] + x[28] + x[29] - x[30] - x[31] - x[32] - x[33] + x[34] - x[35] + x[36] - x[37] + x[38] + x[39];
|
||||
out[7] = + x[0] + x[1] + x[2] + x[3] - x[4] - x[5] + x[6] + x[7] - x[8] + x[9] + x[10] - x[11] - x[12] - x[13] - x[14] + x[15] - x[16] + x[17] - x[18] + x[19] + x[20] + x[21] + x[22] + x[23] - x[24] - x[25] + x[26] + x[27] - x[28] + x[29] + x[30] - x[31] - x[32] - x[33] - x[34] + x[35] - x[36] + x[37] - x[38] + x[39];
|
||||
out[8] = + x[0] + x[1] + x[2] + x[3] + x[4] - x[5] - x[6] + x[7] + x[8] - x[9] + x[10] + x[11] - x[12] - x[13] - x[14] - x[15] + x[16] - x[17] + x[18] - x[19] + x[20] + x[21] + x[22] + x[23] + x[24] - x[25] - x[26] + x[27] + x[28] - x[29] + x[30] + x[31] - x[32] - x[33] - x[34] - x[35] + x[36] - x[37] + x[38] - x[39];
|
||||
out[9] = + x[0] - x[1] + x[2] + x[3] + x[4] + x[5] - x[6] - x[7] + x[8] + x[9] - x[10] + x[11] + x[12] - x[13] - x[14] - x[15] - x[16] + x[17] - x[18] + x[19] + x[20] - x[21] + x[22] + x[23] + x[24] + x[25] - x[26] - x[27] + x[28] + x[29] - x[30] + x[31] + x[32] - x[33] - x[34] - x[35] - x[36] + x[37] - x[38] + x[39];
|
||||
out[10] = + x[0] + x[1] - x[2] + x[3] + x[4] + x[5] + x[6] - x[7] - x[8] + x[9] + x[10] - x[11] + x[12] + x[13] - x[14] - x[15] - x[16] - x[17] + x[18] - x[19] + x[20] + x[21] - x[22] + x[23] + x[24] + x[25] + x[26] - x[27] - x[28] + x[29] + x[30] - x[31] + x[32] + x[33] - x[34] - x[35] - x[36] - x[37] + x[38] - x[39];
|
||||
out[11] = + x[0] - x[1] + x[2] - x[3] + x[4] + x[5] + x[6] + x[7] - x[8] - x[9] + x[10] + x[11] - x[12] + x[13] + x[14] - x[15] - x[16] - x[17] - x[18] + x[19] + x[20] - x[21] + x[22] - x[23] + x[24] + x[25] + x[26] + x[27] - x[28] - x[29] + x[30] + x[31] - x[32] + x[33] + x[34] - x[35] - x[36] - x[37] - x[38] + x[39];
|
||||
out[12] = + x[0] + x[1] - x[2] + x[3] - x[4] + x[5] + x[6] + x[7] + x[8] - x[9] - x[10] + x[11] + x[12] - x[13] + x[14] + x[15] - x[16] - x[17] - x[18] - x[19] + x[20] + x[21] - x[22] + x[23] - x[24] + x[25] + x[26] + x[27] + x[28] - x[29] - x[30] + x[31] + x[32] - x[33] + x[34] + x[35] - x[36] - x[37] - x[38] - x[39];
|
||||
out[13] = + x[0] - x[1] + x[2] - x[3] + x[4] - x[5] + x[6] + x[7] + x[8] + x[9] - x[10] - x[11] + x[12] + x[13] - x[14] + x[15] + x[16] - x[17] - x[18] - x[19] + x[20] - x[21] + x[22] - x[23] + x[24] - x[25] + x[26] + x[27] + x[28] + x[29] - x[30] - x[31] + x[32] + x[33] - x[34] + x[35] + x[36] - x[37] - x[38] - x[39];
|
||||
out[14] = + x[0] - x[1] - x[2] + x[3] - x[4] + x[5] - x[6] + x[7] + x[8] + x[9] + x[10] - x[11] - x[12] + x[13] + x[14] - x[15] + x[16] + x[17] - x[18] - x[19] + x[20] - x[21] - x[22] + x[23] - x[24] + x[25] - x[26] + x[27] + x[28] + x[29] + x[30] - x[31] - x[32] + x[33] + x[34] - x[35] + x[36] + x[37] - x[38] - x[39];
|
||||
out[15] = + x[0] - x[1] - x[2] - x[3] + x[4] - x[5] + x[6] - x[7] + x[8] + x[9] + x[10] + x[11] - x[12] - x[13] + x[14] + x[15] - x[16] + x[17] + x[18] - x[19] + x[20] - x[21] - x[22] - x[23] + x[24] - x[25] + x[26] - x[27] + x[28] + x[29] + x[30] + x[31] - x[32] - x[33] + x[34] + x[35] - x[36] + x[37] + x[38] - x[39];
|
||||
out[16] = + x[0] - x[1] - x[2] - x[3] - x[4] + x[5] - x[6] + x[7] - x[8] + x[9] + x[10] + x[11] + x[12] - x[13] - x[14] + x[15] + x[16] - x[17] + x[18] + x[19] + x[20] - x[21] - x[22] - x[23] - x[24] + x[25] - x[26] + x[27] - x[28] + x[29] + x[30] + x[31] + x[32] - x[33] - x[34] + x[35] + x[36] - x[37] + x[38] + x[39];
|
||||
out[17] = + x[0] + x[1] - x[2] - x[3] - x[4] - x[5] + x[6] - x[7] + x[8] - x[9] + x[10] + x[11] + x[12] + x[13] - x[14] - x[15] + x[16] + x[17] - x[18] + x[19] + x[20] + x[21] - x[22] - x[23] - x[24] - x[25] + x[26] - x[27] + x[28] - x[29] + x[30] + x[31] + x[32] + x[33] - x[34] - x[35] + x[36] + x[37] - x[38] + x[39];
|
||||
out[18] = + x[0] + x[1] + x[2] - x[3] - x[4] - x[5] - x[6] + x[7] - x[8] + x[9] - x[10] + x[11] + x[12] + x[13] + x[14] - x[15] - x[16] + x[17] + x[18] - x[19] + x[20] + x[21] + x[22] - x[23] - x[24] - x[25] - x[26] + x[27] - x[28] + x[29] - x[30] + x[31] + x[32] + x[33] + x[34] - x[35] - x[36] + x[37] + x[38] - x[39];
|
||||
out[19] = + x[0] - x[1] + x[2] + x[3] - x[4] - x[5] - x[6] - x[7] + x[8] - x[9] + x[10] - x[11] + x[12] + x[13] + x[14] + x[15] - x[16] - x[17] + x[18] + x[19] + x[20] - x[21] + x[22] + x[23] - x[24] - x[25] - x[26] - x[27] + x[28] - x[29] + x[30] - x[31] + x[32] + x[33] + x[34] + x[35] - x[36] - x[37] + x[38] + x[39];
|
||||
out[20] = + x[0] - x[1] - x[2] - x[3] - x[4] - x[5] - x[6] - x[7] - x[8] - x[9] - x[10] - x[11] - x[12] - x[13] - x[14] - x[15] - x[16] - x[17] - x[18] - x[19] - x[20] + x[21] + x[22] + x[23] + x[24] + x[25] + x[26] + x[27] + x[28] + x[29] + x[30] + x[31] + x[32] + x[33] + x[34] + x[35] + x[36] + x[37] + x[38] + x[39];
|
||||
out[21] = + x[0] + x[1] - x[2] + x[3] + x[4] - x[5] - x[6] - x[7] - x[8] + x[9] - x[10] + x[11] - x[12] + x[13] + x[14] + x[15] + x[16] - x[17] - x[18] + x[19] - x[20] - x[21] + x[22] - x[23] - x[24] + x[25] + x[26] + x[27] + x[28] - x[29] + x[30] - x[31] + x[32] - x[33] - x[34] - x[35] - x[36] + x[37] + x[38] - x[39];
|
||||
out[22] = + x[0] + x[1] + x[2] - x[3] + x[4] + x[5] - x[6] - x[7] - x[8] - x[9] + x[10] - x[11] + x[12] - x[13] + x[14] + x[15] + x[16] + x[17] - x[18] - x[19] - x[20] - x[21] - x[22] + x[23] - x[24] - x[25] + x[26] + x[27] + x[28] + x[29] - x[30] + x[31] - x[32] + x[33] - x[34] - x[35] - x[36] - x[37] + x[38] + x[39];
|
||||
out[23] = + x[0] - x[1] + x[2] + x[3] - x[4] + x[5] + x[6] - x[7] - x[8] - x[9] - x[10] + x[11] - x[12] + x[13] - x[14] + x[15] + x[16] + x[17] + x[18] - x[19] - x[20] + x[21] - x[22] - x[23] + x[24] - x[25] - x[26] + x[27] + x[28] + x[29] + x[30] - x[31] + x[32] - x[33] + x[34] - x[35] - x[36] - x[37] - x[38] + x[39];
|
||||
out[24] = + x[0] - x[1] - x[2] + x[3] + x[4] - x[5] + x[6] + x[7] - x[8] - x[9] - x[10] - x[11] + x[12] - x[13] + x[14] - x[15] + x[16] + x[17] + x[18] + x[19] - x[20] + x[21] + x[22] - x[23] - x[24] + x[25] - x[26] - x[27] + x[28] + x[29] + x[30] + x[31] - x[32] + x[33] - x[34] + x[35] - x[36] - x[37] - x[38] - x[39];
|
||||
out[25] = + x[0] + x[1] - x[2] - x[3] + x[4] + x[5] - x[6] + x[7] + x[8] - x[9] - x[10] - x[11] - x[12] + x[13] - x[14] + x[15] - x[16] + x[17] + x[18] + x[19] - x[20] - x[21] + x[22] + x[23] - x[24] - x[25] + x[26] - x[27] - x[28] + x[29] + x[30] + x[31] + x[32] - x[33] + x[34] - x[35] + x[36] - x[37] - x[38] - x[39];
|
||||
out[26] = + x[0] + x[1] + x[2] - x[3] - x[4] + x[5] + x[6] - x[7] + x[8] + x[9] - x[10] - x[11] - x[12] - x[13] + x[14] - x[15] + x[16] - x[17] + x[18] + x[19] - x[20] - x[21] - x[22] + x[23] + x[24] - x[25] - x[26] + x[27] - x[28] - x[29] + x[30] + x[31] + x[32] + x[33] - x[34] + x[35] - x[36] + x[37] - x[38] - x[39];
|
||||
out[27] = + x[0] + x[1] + x[2] + x[3] - x[4] - x[5] + x[6] + x[7] - x[8] + x[9] + x[10] - x[11] - x[12] - x[13] - x[14] + x[15] - x[16] + x[17] - x[18] + x[19] - x[20] - x[21] - x[22] - x[23] + x[24] + x[25] - x[26] - x[27] + x[28] - x[29] - x[30] + x[31] + x[32] + x[33] + x[34] - x[35] + x[36] - x[37] + x[38] - x[39];
|
||||
out[28] = + x[0] + x[1] + x[2] + x[3] + x[4] - x[5] - x[6] + x[7] + x[8] - x[9] + x[10] + x[11] - x[12] - x[13] - x[14] - x[15] + x[16] - x[17] + x[18] - x[19] - x[20] - x[21] - x[22] - x[23] - x[24] + x[25] + x[26] - x[27] - x[28] + x[29] - x[30] - x[31] + x[32] + x[33] + x[34] + x[35] - x[36] + x[37] - x[38] + x[39];
|
||||
out[29] = + x[0] - x[1] + x[2] + x[3] + x[4] + x[5] - x[6] - x[7] + x[8] + x[9] - x[10] + x[11] + x[12] - x[13] - x[14] - x[15] - x[16] + x[17] - x[18] + x[19] - x[20] + x[21] - x[22] - x[23] - x[24] - x[25] + x[26] + x[27] - x[28] - x[29] + x[30] - x[31] - x[32] + x[33] + x[34] + x[35] + x[36] - x[37] + x[38] - x[39];
|
||||
out[30] = + x[0] + x[1] - x[2] + x[3] + x[4] + x[5] + x[6] - x[7] - x[8] + x[9] + x[10] - x[11] + x[12] + x[13] - x[14] - x[15] - x[16] - x[17] + x[18] - x[19] - x[20] - x[21] + x[22] - x[23] - x[24] - x[25] - x[26] + x[27] + x[28] - x[29] - x[30] + x[31] - x[32] - x[33] + x[34] + x[35] + x[36] + x[37] - x[38] + x[39];
|
||||
out[31] = + x[0] - x[1] + x[2] - x[3] + x[4] + x[5] + x[6] + x[7] - x[8] - x[9] + x[10] + x[11] - x[12] + x[13] + x[14] - x[15] - x[16] - x[17] - x[18] + x[19] - x[20] + x[21] - x[22] + x[23] - x[24] - x[25] - x[26] - x[27] + x[28] + x[29] - x[30] - x[31] + x[32] - x[33] - x[34] + x[35] + x[36] + x[37] + x[38] - x[39];
|
||||
out[32] = + x[0] + x[1] - x[2] + x[3] - x[4] + x[5] + x[6] + x[7] + x[8] - x[9] - x[10] + x[11] + x[12] - x[13] + x[14] + x[15] - x[16] - x[17] - x[18] - x[19] - x[20] - x[21] + x[22] - x[23] + x[24] - x[25] - x[26] - x[27] - x[28] + x[29] + x[30] - x[31] - x[32] + x[33] - x[34] - x[35] + x[36] + x[37] + x[38] + x[39];
|
||||
out[33] = + x[0] - x[1] + x[2] - x[3] + x[4] - x[5] + x[6] + x[7] + x[8] + x[9] - x[10] - x[11] + x[12] + x[13] - x[14] + x[15] + x[16] - x[17] - x[18] - x[19] - x[20] + x[21] - x[22] + x[23] - x[24] + x[25] - x[26] - x[27] - x[28] - x[29] + x[30] + x[31] - x[32] - x[33] + x[34] - x[35] - x[36] + x[37] + x[38] + x[39];
|
||||
out[34] = + x[0] - x[1] - x[2] + x[3] - x[4] + x[5] - x[6] + x[7] + x[8] + x[9] + x[10] - x[11] - x[12] + x[13] + x[14] - x[15] + x[16] + x[17] - x[18] - x[19] - x[20] + x[21] + x[22] - x[23] + x[24] - x[25] + x[26] - x[27] - x[28] - x[29] - x[30] + x[31] + x[32] - x[33] - x[34] + x[35] - x[36] - x[37] + x[38] + x[39];
|
||||
out[35] = + x[0] - x[1] - x[2] - x[3] + x[4] - x[5] + x[6] - x[7] + x[8] + x[9] + x[10] + x[11] - x[12] - x[13] + x[14] + x[15] - x[16] + x[17] + x[18] - x[19] - x[20] + x[21] + x[22] + x[23] - x[24] + x[25] - x[26] + x[27] - x[28] - x[29] - x[30] - x[31] + x[32] + x[33] - x[34] - x[35] + x[36] - x[37] - x[38] + x[39];
|
||||
out[36] = + x[0] - x[1] - x[2] - x[3] - x[4] + x[5] - x[6] + x[7] - x[8] + x[9] + x[10] + x[11] + x[12] - x[13] - x[14] + x[15] + x[16] - x[17] + x[18] + x[19] - x[20] + x[21] + x[22] + x[23] + x[24] - x[25] + x[26] - x[27] + x[28] - x[29] - x[30] - x[31] - x[32] + x[33] + x[34] - x[35] - x[36] + x[37] - x[38] - x[39];
|
||||
out[37] = + x[0] + x[1] - x[2] - x[3] - x[4] - x[5] + x[6] - x[7] + x[8] - x[9] + x[10] + x[11] + x[12] + x[13] - x[14] - x[15] + x[16] + x[17] - x[18] + x[19] - x[20] - x[21] + x[22] + x[23] + x[24] + x[25] - x[26] + x[27] - x[28] + x[29] - x[30] - x[31] - x[32] - x[33] + x[34] + x[35] - x[36] - x[37] + x[38] - x[39];
|
||||
out[38] = + x[0] + x[1] + x[2] - x[3] - x[4] - x[5] - x[6] + x[7] - x[8] + x[9] - x[10] + x[11] + x[12] + x[13] + x[14] - x[15] - x[16] + x[17] + x[18] - x[19] - x[20] - x[21] - x[22] + x[23] + x[24] + x[25] + x[26] - x[27] + x[28] - x[29] + x[30] - x[31] - x[32] - x[33] - x[34] + x[35] + x[36] - x[37] - x[38] + x[39];
|
||||
out[39] = + x[0] - x[1] + x[2] + x[3] - x[4] - x[5] - x[6] - x[7] + x[8] - x[9] + x[10] - x[11] + x[12] + x[13] + x[14] + x[15] - x[16] - x[17] + x[18] + x[19] - x[20] + x[21] - x[22] - x[23] + x[24] + x[25] + x[26] + x[27] - x[28] + x[29] - x[30] + x[31] - x[32] - x[33] - x[34] - x[35] + x[36] + x[37] - x[38] - x[39];
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 40; i++) { x[i] = out[i]; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
// Inspired by https://github.com/NVIDIA/DALI/blob/main/include/dali/core/static_switch.h
|
||||
// and https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/Dispatch.h
|
||||
|
||||
#pragma once
|
||||
|
||||
/// @param COND - a boolean expression to switch by
|
||||
/// @param CONST_NAME - a name given for the constexpr bool variable.
|
||||
/// @param ... - code to execute for true and false
|
||||
///
|
||||
/// Usage:
|
||||
/// ```
|
||||
/// BOOL_SWITCH(flag, BoolConst, [&] {
|
||||
/// some_function<BoolConst>(...);
|
||||
/// });
|
||||
/// ```
|
||||
#define BOOL_SWITCH(COND, CONST_NAME, ...) \
|
||||
if (COND) { \
|
||||
constexpr static bool CONST_NAME = true; \
|
||||
__VA_ARGS__ \
|
||||
} else { \
|
||||
constexpr static bool CONST_NAME = false; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
@@ -0,0 +1,31 @@
|
||||
|
||||
#include <ATen/cuda/CUDAContext.h>
|
||||
#include <c10/cuda/CUDAGuard.h>
|
||||
|
||||
#include <torch/extension.h>
|
||||
#include <torch/python.h>
|
||||
|
||||
|
||||
at::Tensor rms_norm_rope(at::Tensor &x, c10::optional<at::Tensor>& weights_, at::Tensor &cos_freqs, at::Tensor &sin_freqs, bool out_16bit);
|
||||
|
||||
at::Tensor fp6_pack(at::Tensor &x);
|
||||
at::Tensor fp6_unpack(at::Tensor &x, int64_t original_n);
|
||||
|
||||
at::Tensor rms_norm_split_rope(
|
||||
at::Tensor &x,
|
||||
at::Tensor &sin_freqs,
|
||||
at::Tensor &cos_freqs,
|
||||
at::Tensor &weights,
|
||||
bool out_fp8
|
||||
);
|
||||
|
||||
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
|
||||
m.def("rms_norm_rope", &rms_norm_rope,
|
||||
"fused norm + rope + cvt");
|
||||
m.def("fp6_pack", &fp6_pack,
|
||||
"Pack 8-bit to 6-bit by dropping e_1 and e_2 bits");
|
||||
m.def("fp6_unpack", &fp6_unpack,
|
||||
"Unpack 6-bit to 8-bit (with e_1 and e_2 set to 0)");
|
||||
m.def("rms_norm_split_rope", &rms_norm_split_rope,
|
||||
"RMS norm + split RoPE with optional FP8 output");
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2023, Tri Dao.
|
||||
******************************************************************************/
|
||||
|
||||
// Host entry point for the fused RMS-norm + RoPE kernel.
|
||||
|
||||
#include <ATen/cuda/CUDAContext.h>
|
||||
#include <c10/cuda/CUDAGuard.h>
|
||||
#include <torch/extension.h>
|
||||
#include <vector>
|
||||
|
||||
#include "fast_hadamard_transform.h"
|
||||
|
||||
#define CHECK_SHAPE(x, ...) TORCH_CHECK(x.sizes() == torch::IntArrayRef({__VA_ARGS__}), #x " must have shape (" #__VA_ARGS__ ")")
|
||||
|
||||
template<typename input_t, typename output_t, bool norm_affine>
|
||||
void rms_norm_rope_cuda(NormRopeHadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
|
||||
void set_norm_rope_hadamard_params(NormRopeHadamardParamsBase ¶ms,
|
||||
// sizes
|
||||
const size_t batch,
|
||||
const size_t dim,
|
||||
const size_t multiple,
|
||||
// device pointers
|
||||
const at::Tensor x,
|
||||
const at::Tensor cos_freqs,
|
||||
const at::Tensor sin_freqs,
|
||||
const at::Tensor weights,
|
||||
const at::Tensor out,
|
||||
|
||||
bool norm_affine,
|
||||
float scale
|
||||
) {
|
||||
|
||||
// Reset the parameters
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
|
||||
params.batch = batch;
|
||||
params.dim = dim;
|
||||
params.log_N = int(ceil(std::log2(dim / multiple)));
|
||||
|
||||
// Set the pointers and strides.
|
||||
params.x_ptr = x.data_ptr();
|
||||
params.out_ptr = out.data_ptr();
|
||||
params.cos_freq_ptr = cos_freqs.data_ptr();
|
||||
params.sin_freq_ptr = sin_freqs.data_ptr();
|
||||
if (norm_affine){
|
||||
params.weights_ptr = weights.data_ptr();
|
||||
} else {
|
||||
params.weights_ptr = nullptr;
|
||||
}
|
||||
// All stride are in elements, not bytes.
|
||||
params.x_batch_stride = x.stride(0);
|
||||
params.out_batch_stride = out.stride(0);
|
||||
params.cos_freq_batch_stride = cos_freqs.stride(0);
|
||||
params.sin_freq_batch_stride = sin_freqs.stride(0);
|
||||
|
||||
params.scale = scale;
|
||||
|
||||
}
|
||||
|
||||
at::Tensor rms_norm_rope(at::Tensor &x, c10::optional<at::Tensor>& weights_, at::Tensor &cos_freqs, at::Tensor &sin_freqs, bool out_16bit) {
|
||||
auto input_type = x.scalar_type();
|
||||
float scale = 1.0f; // :D
|
||||
TORCH_CHECK(input_type == at::ScalarType::BFloat16);
|
||||
TORCH_CHECK(x.is_cuda());
|
||||
const auto shapes_og = x.sizes();
|
||||
const int dim_og = x.size(-1);
|
||||
x = x.reshape({-1, dim_og});
|
||||
if (x.stride(-1) != 1) { x = x.contiguous(); }
|
||||
const auto sizes = x.sizes();
|
||||
const int batch_size = sizes[0];
|
||||
cos_freqs = cos_freqs.reshape({-1, dim_og});
|
||||
sin_freqs = sin_freqs.reshape({-1, dim_og});
|
||||
at::Tensor weights;
|
||||
bool norm_affine = false;
|
||||
if(weights_.has_value()){
|
||||
weights = weights_.value();
|
||||
norm_affine = true;
|
||||
}
|
||||
CHECK_SHAPE(x, batch_size, dim_og);
|
||||
TORCH_CHECK(x.stride(1) == 1);
|
||||
if (dim_og % 8 != 0) {
|
||||
x = torch::nn::functional::pad(x, torch::nn::functional::PadFuncOptions({0, 8 - dim_og % 8}));
|
||||
}
|
||||
const int dim = x.size(1);
|
||||
at::Tensor out;
|
||||
if (out_16bit){
|
||||
out = torch::empty(x.sizes(), x.options().dtype(torch::kBFloat16));
|
||||
} else {
|
||||
out = torch::empty(x.sizes(), x.options().dtype(torch::kFloat8_e4m3fn));
|
||||
}
|
||||
at::cuda::CUDAGuard device_guard{(char)x.get_device()};
|
||||
auto stream = at::cuda::getCurrentCUDAStream().stream();
|
||||
NormRopeHadamardParamsBase params;
|
||||
set_norm_rope_hadamard_params(params, batch_size, dim, 1, x, cos_freqs, sin_freqs, weights, out, norm_affine, scale);
|
||||
TORCH_CHECK(dim % 8 == 0, "fast_hadamard_transform only supports hidden dimension divisible by 8 for now");
|
||||
TORCH_CHECK(dim <= 32768, "fast_hadamard_transform only supports hidden dimension at most 32768 for now");
|
||||
if (norm_affine){
|
||||
if (out_16bit){
|
||||
rms_norm_rope_cuda<at::BFloat16, at::BFloat16, true>(params, stream);
|
||||
} else {
|
||||
rms_norm_rope_cuda<at::BFloat16, at::Float8_e4m3fn, true>(params, stream);
|
||||
}
|
||||
|
||||
} else {
|
||||
if (out_16bit){
|
||||
rms_norm_rope_cuda<at::BFloat16, at::BFloat16, false>(params, stream);
|
||||
} else {
|
||||
rms_norm_rope_cuda<at::BFloat16, at::Float8_e4m3fn, false>(params, stream);
|
||||
}
|
||||
}
|
||||
return out.reshape(shapes_og);
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
/******************************************************************************
|
||||
* Copyright (c) 2023, Tri Dao.
|
||||
******************************************************************************/
|
||||
|
||||
// #pragma once
|
||||
|
||||
#include <c10/util/BFloat16.h>
|
||||
#include <c10/util/Half.h>
|
||||
#include <c10/util/Float8_e4m3fn.h>
|
||||
#include <c10/cuda/CUDAException.h> // For C10_CUDA_CHECK and C10_CUDA_KERNEL_LAUNCH_CHECK
|
||||
|
||||
#include "fast_hadamard_transform.h"
|
||||
#include "fast_hadamard_transform_common.h"
|
||||
#include "fast_hadamard_transform_special.h"
|
||||
#include "static_switch.h"
|
||||
|
||||
|
||||
template<int kNThreads_, int kLogN_, typename input_t_, typename output_t_, bool norm_affine_>
|
||||
struct norm_rope_kernel_traits {
|
||||
using input_t = input_t_;
|
||||
using output_t = output_t_;
|
||||
|
||||
static constexpr int kNThreads = kNThreads_;
|
||||
static constexpr int kLogN = kLogN_;
|
||||
static constexpr int N = 1 << kLogN;
|
||||
static constexpr int kNBytes = sizeof(input_t);
|
||||
static constexpr int OutkNBytes = sizeof(output_t);
|
||||
|
||||
static constexpr bool norm_affine = norm_affine_;
|
||||
|
||||
static_assert(kNBytes == 1 || kNBytes == 2 || kNBytes == 4);
|
||||
static constexpr int kNElts = kNBytes == 4 ? 4 : kNBytes == 2 ? 8 : 8;
|
||||
// It's possible that we need to do 2 rounds of exchange if input_t is 16 bits
|
||||
// (since then we'd have 8 values of float, and each round we can exchange 4 floats).
|
||||
static constexpr int kNExchangePerVec = sizeof(float) / sizeof(input_t);
|
||||
|
||||
using vec_t = typename BytesToType<kNBytes * kNElts>::Type;
|
||||
using vec_t_out = typename BytesToType<OutkNBytes * kNElts>::Type;
|
||||
|
||||
static constexpr int kNChunks = N / (kNElts * kNThreads);
|
||||
// We don't want to use more than 32 KB of shared memory.
|
||||
static constexpr int kSmemExchangeSize = std::min(N * 4, 32 * 1024);
|
||||
static constexpr int kNExchangeRounds = N * 4 / kSmemExchangeSize;
|
||||
static_assert(kNExchangeRounds * kSmemExchangeSize == N * 4);
|
||||
static constexpr int kSmemSize = kSmemExchangeSize;
|
||||
};
|
||||
|
||||
|
||||
template<typename Ktraits>
|
||||
__global__ __launch_bounds__(Ktraits::kNThreads)
|
||||
void norm_rope_cvt_kernel(NormRopeHadamardParamsBase params) {
|
||||
constexpr int kNThreads = Ktraits::kNThreads;
|
||||
constexpr int kNElts = Ktraits::kNElts;
|
||||
constexpr int kNExchangePerVec = Ktraits::kNExchangePerVec;
|
||||
constexpr int kNExchangeRounds = Ktraits::kNExchangeRounds;
|
||||
constexpr int kNChunks = Ktraits::kNChunks;
|
||||
constexpr bool norm_affine = Ktraits::norm_affine;
|
||||
|
||||
using input_t = typename Ktraits::input_t;
|
||||
using output_t = typename Ktraits::output_t;
|
||||
using vec_t = typename Ktraits::vec_t;
|
||||
using out_vec_t = typename Ktraits::vec_t_out;
|
||||
using weights_t = typename Ktraits::input_t;
|
||||
using freqs_t = typename Ktraits::input_t;
|
||||
|
||||
constexpr int kLogNElts = cilog2(Ktraits::kNElts);
|
||||
static_assert(1 << kLogNElts == kNElts, "kNElts must be a power of 2");
|
||||
constexpr int kWarpSize = std::min(kNThreads, 32);
|
||||
constexpr int kLogWarpSize = cilog2(kWarpSize);
|
||||
static_assert(1 << kLogWarpSize == kWarpSize, "Warp size must be a power of 2");
|
||||
constexpr int kNWarps = kNThreads / kWarpSize;
|
||||
constexpr int kLogNWarps = cilog2(kNWarps);
|
||||
static_assert(1 << kLogNWarps == kNWarps, "kNWarps must be a power of 2");
|
||||
constexpr int kLoadsPerExchange = Ktraits::kSmemExchangeSize / (sizeof(vec_t) * kNThreads);
|
||||
static_assert(kLoadsPerExchange * sizeof(vec_t) * kNThreads == Ktraits::kSmemExchangeSize, "kSmemExchangeSize should be a power of 2");
|
||||
static_assert(kNExchangeRounds * kLoadsPerExchange * sizeof(vec_t) == kNChunks * kNElts * sizeof(float));
|
||||
|
||||
constexpr int kChunksPerExchange = Ktraits::kSmemExchangeSize / (sizeof(vec_t) * kNExchangePerVec * kNThreads);
|
||||
static_assert(kChunksPerExchange * sizeof(vec_t) * kNExchangePerVec * kNThreads == Ktraits::kSmemExchangeSize);
|
||||
constexpr int kNExchanges = kNChunks / kChunksPerExchange;
|
||||
static_assert(kNExchanges * kChunksPerExchange == kNChunks);
|
||||
|
||||
// Shared memory.
|
||||
extern __shared__ char smem_[];
|
||||
vec_t *smem_exchange = reinterpret_cast<vec_t *>(smem_);
|
||||
|
||||
const int batch_id = blockIdx.x;
|
||||
const int warp_id = threadIdx.x / 32;
|
||||
|
||||
input_t *x = reinterpret_cast<input_t *>(params.x_ptr) + batch_id * params.x_batch_stride;
|
||||
output_t *out = reinterpret_cast<output_t *>(params.out_ptr) + batch_id * params.out_batch_stride;
|
||||
weights_t *weights = norm_affine ? reinterpret_cast<weights_t*>(params.weights_ptr) : nullptr;
|
||||
|
||||
float x_vals[kNChunks][kNElts];
|
||||
float weights_vals[kNChunks][kNElts];
|
||||
|
||||
load_input<kNChunks, kNElts, input_t>(x, x_vals, params.dim);
|
||||
|
||||
//RMS Norm START
|
||||
float thread_squared_sum = 0.0f;
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i++)
|
||||
{
|
||||
thread_squared_sum += x_vals[c][i] * x_vals[c][i];
|
||||
}
|
||||
|
||||
}
|
||||
SumOp<float> sum_op;
|
||||
float warp_sum = Allreduce<32>::run(thread_squared_sum, sum_op);
|
||||
float *smem_sum = reinterpret_cast<float*>(smem_);
|
||||
if(threadIdx.x % 32 == 0){
|
||||
smem_sum[warp_id] = warp_sum;
|
||||
}
|
||||
__syncthreads();
|
||||
float norm = 0.0f;
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNWarps; i++)
|
||||
{
|
||||
norm += smem_sum[i];
|
||||
}
|
||||
|
||||
norm *= 1.0f/params.dim;
|
||||
norm = rsqrtf(norm);
|
||||
if constexpr (norm_affine){
|
||||
load_input<kNChunks, kNElts, weights_t>(weights, weights_vals, params.dim);
|
||||
}
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i++)
|
||||
{
|
||||
if constexpr (norm_affine){
|
||||
x_vals[c][i] *= (norm * weights_vals[c][i]);
|
||||
} else {
|
||||
x_vals[c][i] *= norm;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//RMS NORM END
|
||||
|
||||
//ROPE START
|
||||
float sin_freqs_vals[kNChunks][kNElts];
|
||||
float cos_freqs_vals[kNChunks][kNElts];
|
||||
|
||||
freqs_t *cos_freqs = reinterpret_cast<freqs_t*>(params.cos_freq_ptr) + batch_id * params.cos_freq_batch_stride;
|
||||
freqs_t *sin_freqs = reinterpret_cast<freqs_t*>(params.sin_freq_ptr) + batch_id * params.sin_freq_batch_stride;
|
||||
|
||||
load_input<kNChunks, kNElts, freqs_t>(cos_freqs, cos_freqs_vals, params.dim);
|
||||
load_input<kNChunks, kNElts, freqs_t>(sin_freqs, sin_freqs_vals, params.dim);
|
||||
|
||||
#pragma unroll
|
||||
for (size_t c = 0; c < kNChunks; c++)
|
||||
{
|
||||
#pragma unroll
|
||||
for (size_t i = 0; i < kNElts; i+=2)
|
||||
{
|
||||
float x_1 = x_vals[c][i];
|
||||
float x_2 = x_vals[c][i+1];
|
||||
x_vals[c][i] = -x_2*sin_freqs_vals[c][i] + x_1*cos_freqs_vals[c][i];
|
||||
x_vals[c][i+1] = x_1*sin_freqs_vals[c][i+1] + x_2*cos_freqs_vals[c][i+1];
|
||||
}
|
||||
}
|
||||
//ROPE END
|
||||
|
||||
store_output<kNChunks, kNElts, output_t, false>(out, x_vals, params.dim, params.scale);
|
||||
}
|
||||
|
||||
template<int kNThreads, int kLogN, typename input_t, typename output_t, bool norm_affine>
|
||||
void norm_rope_cvt_launch(NormRopeHadamardParamsBase ¶ms, cudaStream_t stream) {
|
||||
using Ktraits = norm_rope_kernel_traits<kNThreads, kLogN, input_t, output_t, norm_affine>;
|
||||
constexpr int kSmemSize = Ktraits::kSmemSize;
|
||||
dim3 grid(params.batch);
|
||||
auto kernel = &norm_rope_cvt_kernel<Ktraits>;
|
||||
if (kSmemSize >= 48 * 1024) {
|
||||
C10_CUDA_CHECK(cudaFuncSetAttribute(
|
||||
kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, kSmemSize));
|
||||
}
|
||||
kernel<<<grid, Ktraits::kNThreads, kSmemSize, stream>>>(params);
|
||||
C10_CUDA_KERNEL_LAUNCH_CHECK();
|
||||
}
|
||||
|
||||
template<typename input_t, typename output_t, bool norm_affine>
|
||||
void rms_norm_rope_cuda(NormRopeHadamardParamsBase ¶ms, cudaStream_t stream) {
|
||||
if (params.log_N == 3) {
|
||||
norm_rope_cvt_launch<1, 3, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 4) {
|
||||
norm_rope_cvt_launch<2, 4, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 5) {
|
||||
norm_rope_cvt_launch<4, 5, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 6) {
|
||||
norm_rope_cvt_launch<8, 6, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 7) {
|
||||
norm_rope_cvt_launch<16, 7, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 8) {
|
||||
norm_rope_cvt_launch<32, 8, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 9) {
|
||||
norm_rope_cvt_launch<32, 9, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 10) {
|
||||
norm_rope_cvt_launch<128, 10, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 11) {
|
||||
norm_rope_cvt_launch<256, 11, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 12) {
|
||||
norm_rope_cvt_launch<256, 12, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 13) {
|
||||
norm_rope_cvt_launch<256, 13, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 14) {
|
||||
norm_rope_cvt_launch<256, 14, input_t, output_t, norm_affine>(params, stream);
|
||||
} else if (params.log_N == 15) {
|
||||
norm_rope_cvt_launch<256, 15, input_t, output_t, norm_affine>(params, stream);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template void rms_norm_rope_cuda<at::BFloat16, at::Float8_e4m3fn, false>(NormRopeHadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
template void rms_norm_rope_cuda<at::BFloat16, at::Float8_e4m3fn, true>(NormRopeHadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
|
||||
template void rms_norm_rope_cuda<at::BFloat16, at::BFloat16, false>(NormRopeHadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
template void rms_norm_rope_cuda<at::BFloat16, at::BFloat16, true>(NormRopeHadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
|
||||
// template void fast_hadamard_transform_cuda<at::BFloat16, at::BFloat16>(HadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
|
||||
// template void fast_hadamard_transform_cuda<at::Float8_e4m3fn, at::BFloat16>(HadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
// template void fast_hadamard_transform_cuda<at::Float8_e4m3fn, at::Float8_e4m3fn>(HadamardParamsBase ¶ms, cudaStream_t stream);
|
||||
@@ -0,0 +1,111 @@
|
||||
#include <ATen/cuda/CUDAContext.h>
|
||||
#include <c10/cuda/CUDAGuard.h>
|
||||
#include <torch/extension.h>
|
||||
#include <torch/python.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Forward declaration of CUDA kernel template
|
||||
template<typename out_t>
|
||||
void rms_norm_split_rope_cuda(
|
||||
void* x,
|
||||
void* sin_freqs,
|
||||
void* cos_freqs,
|
||||
void* weights,
|
||||
int b,
|
||||
int s,
|
||||
int n,
|
||||
int h,
|
||||
long cos_sb, long cos_sn, long cos_ss,
|
||||
long sin_sb, long sin_sn, long sin_ss,
|
||||
void* out,
|
||||
cudaStream_t stream
|
||||
);
|
||||
|
||||
at::Tensor rms_norm_split_rope(
|
||||
at::Tensor &x,
|
||||
at::Tensor &sin_freqs,
|
||||
at::Tensor &cos_freqs,
|
||||
at::Tensor &weights,
|
||||
bool out_fp8
|
||||
) {
|
||||
TORCH_CHECK(x.scalar_type() == at::ScalarType::BFloat16, "Input must be BFloat16");
|
||||
TORCH_CHECK(sin_freqs.scalar_type() == at::ScalarType::BFloat16, "sin_freqs must be BFloat16");
|
||||
TORCH_CHECK(cos_freqs.scalar_type() == at::ScalarType::BFloat16, "cos_freqs must be BFloat16");
|
||||
TORCH_CHECK(x.is_cuda(), "Input must be on CUDA");
|
||||
TORCH_CHECK(sin_freqs.is_cuda(), "sin_freqs must be on CUDA");
|
||||
TORCH_CHECK(cos_freqs.is_cuda(), "cos_freqs must be on CUDA");
|
||||
|
||||
// Get dimensions
|
||||
// x: [b, s, h]
|
||||
// cos, sin: [b, n, s, d] where n*d = h/2
|
||||
int b = x.size(0);
|
||||
int s = x.size(1);
|
||||
int h = x.size(2);
|
||||
|
||||
TORCH_CHECK(cos_freqs.dim() == 4, "cos_freqs must be 4D");
|
||||
TORCH_CHECK(sin_freqs.dim() == 4, "sin_freqs must be 4D");
|
||||
|
||||
int n = cos_freqs.size(1);
|
||||
int d = h / n;
|
||||
|
||||
|
||||
// Require a contiguous innermost (d/2) dim for the vectorized int4 freq load,
|
||||
// but keep the outer (b, n, s) strides: apply_split_rotary_emb hands us a
|
||||
// swapaxes view (logical [b, n, s, d/2], physical [b, s, n, d/2]) whose inner
|
||||
// stride is already 1, so this never copies it. The strides are forwarded to
|
||||
// the kernel so the read is correct regardless of the physical layout.
|
||||
if (x.stride(-1) != 1) { x = x.contiguous(); }
|
||||
if (cos_freqs.stride(-1) != 1) { cos_freqs = cos_freqs.contiguous(); }
|
||||
if (sin_freqs.stride(-1) != 1) { sin_freqs = sin_freqs.contiguous(); }
|
||||
|
||||
long cos_sb = cos_freqs.stride(0), cos_sn = cos_freqs.stride(1), cos_ss = cos_freqs.stride(2);
|
||||
long sin_sb = sin_freqs.stride(0), sin_sn = sin_freqs.stride(1), sin_ss = sin_freqs.stride(2);
|
||||
|
||||
// Create output tensor
|
||||
at::Tensor out;
|
||||
if (out_fp8) {
|
||||
out = torch::empty(x.sizes(), x.options().dtype(torch::kFloat8_e4m3fn));
|
||||
} else {
|
||||
out = torch::empty(x.sizes(), x.options().dtype(torch::kBFloat16));
|
||||
}
|
||||
|
||||
// Setup CUDA
|
||||
at::cuda::CUDAGuard device_guard{(char)x.get_device()};
|
||||
auto stream = at::cuda::getCurrentCUDAStream().stream();
|
||||
|
||||
// Launch kernel
|
||||
if (out_fp8) {
|
||||
rms_norm_split_rope_cuda<at::Float8_e4m3fn>(
|
||||
x.data_ptr(),
|
||||
sin_freqs.data_ptr(),
|
||||
cos_freqs.data_ptr(),
|
||||
weights.data_ptr(), // weights (optional, not used yet)
|
||||
b,
|
||||
s,
|
||||
n,
|
||||
h,
|
||||
cos_sb, cos_sn, cos_ss,
|
||||
sin_sb, sin_sn, sin_ss,
|
||||
(void*)out.data_ptr(),
|
||||
stream
|
||||
);
|
||||
} else {
|
||||
rms_norm_split_rope_cuda<at::BFloat16>(
|
||||
x.data_ptr(),
|
||||
sin_freqs.data_ptr(),
|
||||
cos_freqs.data_ptr(),
|
||||
weights.data_ptr(), // weights (optional, not used yet)
|
||||
b,
|
||||
s,
|
||||
n,
|
||||
h,
|
||||
cos_sb, cos_sn, cos_ss,
|
||||
sin_sb, sin_sn, sin_ss,
|
||||
(void*)out.data_ptr(),
|
||||
stream
|
||||
);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
#include <c10/util/BFloat16.h>
|
||||
#include <c10/util/Float8_e4m3fn.h>
|
||||
#include <c10/cuda/CUDAException.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <cuda_bf16.h>
|
||||
#include <cuda_fp8.h>
|
||||
|
||||
// CUDA kernel template for RMS norm + split RoPE
|
||||
// out_t can be at::Float8_e4m3fn or at::BFloat16
|
||||
|
||||
using bf16 = __nv_bfloat16;
|
||||
using fp8 = __nv_fp8_e4m3;
|
||||
__device__ __forceinline__ void _load_x(bf16* x, float x_vals[8], int h){
|
||||
bf16 x_tmp[8];
|
||||
*reinterpret_cast<int4*>(x_tmp) = reinterpret_cast<int4*>(x + blockIdx.x * h)[threadIdx.x];
|
||||
#pragma unroll
|
||||
for(int i = 0; i < 8; i++){
|
||||
x_vals[i] = float(x_tmp[i]);
|
||||
}
|
||||
}
|
||||
// Load 8 freq values for this thread from a table laid out logically as
|
||||
// [b, n, s, d/2] (what apply_split_rotary_emb produces -- a swapaxes view whose
|
||||
// physical layout is [b, s, n, d/2]). The strides (sb, sn, ss; inner d/2 stride
|
||||
// is 1) are forwarded from the host so the read is correct for both that
|
||||
// non-contiguous view and a genuinely contiguous [b, n, s, d/2] tensor. Both
|
||||
// head-halves map to the same freq element (mirrors the eager cos.unsqueeze(-2)).
|
||||
__device__ __forceinline__ void _load_freqs(
|
||||
const bf16* freqs, float x_vals[8], int s, int d, long sb, long sn, long ss
|
||||
){
|
||||
bf16 x_tmp[8];
|
||||
int threads_per_head = d / 8;
|
||||
int head_idx = threadIdx.x / threads_per_head;
|
||||
int lane = threadIdx.x % (threads_per_head / 2);
|
||||
int b_idx = blockIdx.x / s;
|
||||
int t_idx = blockIdx.x % s;
|
||||
long off = b_idx * sb + head_idx * sn + t_idx * ss + (long)lane * 8;
|
||||
*reinterpret_cast<int4*>(x_tmp) = *reinterpret_cast<const int4*>(freqs + off);
|
||||
#pragma unroll
|
||||
for(int i = 0; i < 8; i++){
|
||||
x_vals[i] = float(x_tmp[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename out_t>
|
||||
__global__ void _rms_norm_split_rope_kernel(bf16* x, bf16* sin_freqs, bf16* cos_freqs, void* out, bf16* weights, int b, int s, int n, int h,
|
||||
long cos_sb, long cos_sn, long cos_ss, long sin_sb, long sin_sn, long sin_ss){
|
||||
int token_idx = blockIdx.x;
|
||||
int tid = threadIdx.x;
|
||||
int lane_id = tid % 32;
|
||||
// freqs have shape [b, s, h/2]
|
||||
// each thread block calculate one row
|
||||
// there are h/8 threads in thread block, each thread processes 8 values
|
||||
// num_of_rows = b * s
|
||||
// freqs have h/2 dim
|
||||
// gridDim is (num_of_rows, 1, 1)
|
||||
// calculate rms norm x_normed = x/x_norm * weights. x_norm is calculated across row, it means thread block wide sum reduction
|
||||
|
||||
extern __shared__ float smem[];
|
||||
|
||||
// Step 1: Load input values (8 per thread)
|
||||
float x_vals[8];
|
||||
_load_x(x, x_vals, h);
|
||||
|
||||
float sum_sq = 0.0f;
|
||||
#pragma unroll
|
||||
for(int i = 0; i < 8; i++){
|
||||
sum_sq += x_vals[i] * x_vals[i];
|
||||
}
|
||||
|
||||
// Warp-level reduction
|
||||
#pragma unroll
|
||||
for(int offset = 16; offset > 0; offset >>= 1){
|
||||
sum_sq += __shfl_xor_sync(0xffffffff, sum_sq, offset);
|
||||
}
|
||||
|
||||
if(tid % 32 == 0){
|
||||
smem[tid / 32] = sum_sq;
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
// Final reduction across warps
|
||||
if(tid == 0){
|
||||
float total_sum = 0.0f;
|
||||
int num_warps = blockDim.x / 32;
|
||||
for(int i = 0; i < num_warps; i++){
|
||||
total_sum += smem[i];
|
||||
}
|
||||
// RMS: sqrt(mean(x^2))
|
||||
float rms = rsqrtf(total_sum / h + 1e-6f); // Add epsilon for numerical stability
|
||||
smem[0] = rms;
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
float inv_rms = smem[0];
|
||||
|
||||
// Step 3: Apply RMS normalization (and weights if provided)
|
||||
#pragma unroll
|
||||
for(int i = 0; i < 8; i++){
|
||||
x_vals[i] *= inv_rms;
|
||||
// TODO: Apply weights if provided
|
||||
if(weights != nullptr) x_vals[i] *= float(weights[tid * 8 + i]);
|
||||
}
|
||||
|
||||
// Step 4: Calculate dimensions for split RoPE
|
||||
// Conceptually: [b, s, h] -> [b, s, n, 2*d] -> [b, s, n, 2, d]
|
||||
// where h = n * 2 * d
|
||||
int d = h / n;
|
||||
float x_other_vals[8];
|
||||
|
||||
int threads_per_head = d / 8;
|
||||
int head_idx = tid / threads_per_head;
|
||||
int idx_in_head = tid % threads_per_head;
|
||||
bool is_first_half = idx_in_head < (threads_per_head / 2);
|
||||
|
||||
// LT-PATCH: full-warp mask. The original (1u << threads_per_head) - 1 only marks
|
||||
// the first head's lanes active, so lanes belonging to heads beyond the first are
|
||||
// not in the mask -> __shfl_xor_sync result is undefined and can corrupt RoPE. The
|
||||
// XOR pattern keeps data within each power-of-two head group, so a full-warp mask
|
||||
// is correct for every lane.
|
||||
const unsigned mask = 0xffffffffu;
|
||||
const int laneMask = threads_per_head / 2; // 4, 8, or 16
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 8; i++) {
|
||||
x_other_vals[i] = __shfl_xor_sync(mask, x_vals[i], laneMask);
|
||||
}
|
||||
|
||||
float cos_vals[8], sin_vals[8];
|
||||
_load_freqs(cos_freqs, cos_vals, s, d, cos_sb, cos_sn, cos_ss);
|
||||
_load_freqs(sin_freqs, sin_vals, s, d, sin_sb, sin_sn, sin_ss);
|
||||
#pragma unroll
|
||||
for(int i = 0; i < 8; i++){
|
||||
x_vals[i] = cos_vals[i]*x_vals[i];
|
||||
}
|
||||
|
||||
|
||||
float sign = is_first_half ? -1.0f : 1.0f;
|
||||
for(int i = 0; i < 8; i++){
|
||||
x_vals[i] += sign*sin_vals[i]*x_other_vals[i];
|
||||
}
|
||||
|
||||
// Step 6: Convert and store output
|
||||
if constexpr (std::is_same_v<out_t, at::Float8_e4m3fn>){
|
||||
fp8 out_tmp[8];
|
||||
#pragma unroll
|
||||
for(int i = 0; i < 8; i++){
|
||||
out_tmp[i] = fp8(x_vals[i]);
|
||||
}
|
||||
*reinterpret_cast<int64_t*>((fp8*)out + token_idx * h + tid * 8) = *reinterpret_cast<int64_t*>(out_tmp);
|
||||
} else {
|
||||
bf16 out_tmp[8];
|
||||
#pragma unroll
|
||||
for(int i = 0; i < 8; i++){
|
||||
out_tmp[i] = __float2bfloat16(x_vals[i]);
|
||||
}
|
||||
*reinterpret_cast<int4*>((bf16*)out + token_idx * h + tid * 8) = *reinterpret_cast<int4*>(out_tmp);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename out_t>
|
||||
void rms_norm_split_rope_cuda(
|
||||
void* x, // Input: [b, s, h]
|
||||
void* sin_freqs, // Sin frequencies: [b, n, s, d]
|
||||
void* cos_freqs, // Cos frequencies: [b, n, s, d]
|
||||
void* weights,
|
||||
int b, // Batch size
|
||||
int s, // Sequence length
|
||||
int n, // Number of heads (32)
|
||||
int h, // Hidden dimension (2048, 4096, or 8192)
|
||||
long cos_sb, long cos_sn, long cos_ss, // cos_freqs strides (b, n, s)
|
||||
long sin_sb, long sin_sn, long sin_ss, // sin_freqs strides (b, n, s)
|
||||
void* out, // Output: [b, s, h]
|
||||
cudaStream_t stream
|
||||
) {
|
||||
int num_tokens = b * s;
|
||||
int num_threads = h / 8; // Each thread processes 8 elements
|
||||
int smem_size = (num_threads / 32 + 1) * sizeof(float); // Shared memory for reductions
|
||||
|
||||
dim3 grid(num_tokens);
|
||||
dim3 block(num_threads);
|
||||
|
||||
_rms_norm_split_rope_kernel<out_t><<<grid, block, smem_size, stream>>>(
|
||||
reinterpret_cast<bf16*>(x),
|
||||
reinterpret_cast<bf16*>(sin_freqs),
|
||||
reinterpret_cast<bf16*>(cos_freqs),
|
||||
out,
|
||||
reinterpret_cast<bf16*>(weights),
|
||||
b, s, n, h,
|
||||
cos_sb, cos_sn, cos_ss,
|
||||
sin_sb, sin_sn, sin_ss
|
||||
);
|
||||
|
||||
C10_CUDA_KERNEL_LAUNCH_CHECK();
|
||||
}
|
||||
|
||||
// Explicit template instantiations
|
||||
template void rms_norm_split_rope_cuda<at::BFloat16>(
|
||||
void*, void*, void*, void*, int, int, int, int, long, long, long, long, long, long, void*, cudaStream_t
|
||||
);
|
||||
|
||||
template void rms_norm_split_rope_cuda<at::Float8_e4m3fn>(
|
||||
void*, void*, void*, void*, int, int, int, int, long, long, long, long, long, long, void*, cudaStream_t
|
||||
);
|
||||
Reference in New Issue
Block a user