#include "neuroflow/rope.hpp" #include #include #ifdef USE_CUDA #include "cuda_context.hpp" #endif namespace neuroflow { RoPE::RoPE(size_t head_dim, size_t max_seq_len) : head_dim_(head_dim), max_seq_len_(max_seq_len), freqs_cos_({max_seq_len, head_dim / 2}, QuantType::FP32), freqs_sin_({max_seq_len, head_dim / 2}, QuantType::FP32) { float* cos_p = freqs_cos_.as_fp32(); float* sin_p = freqs_sin_.as_fp32(); float base = 10000.0f; size_t half_dim = head_dim / 2; for (size_t pos = 0; pos < max_seq_len; ++pos) { for (size_t d = 0; d < half_dim; ++d) { float freq = 1.0f / std::pow(base, static_cast(2 * d) / static_cast(head_dim)); float angle = static_cast(pos) * freq; cos_p[pos * half_dim + d] = std::cos(angle); sin_p[pos * half_dim + d] = std::sin(angle); } } #ifdef USE_CUDA if (CudaContext::instance().is_available()) { freqs_cos_.to_gpu(); freqs_sin_.to_gpu(); } #endif } void RoPE::apply(Tensor& qkv, size_t seq_len, size_t n_heads, size_t d_model, size_t offset) const { size_t half_dim = head_dim_ / 2; #ifdef USE_CUDA if (CudaContext::instance().is_available() && qkv.is_on_gpu()) { launch_rope(qkv.as_gpu_fp32(), freqs_cos_.as_gpu_fp32(), freqs_sin_.as_gpu_fp32(), seq_len, n_heads, d_model, head_dim_, offset, CudaContext::instance().stream()); qkv.gpu_dirty_ = true; return; } #endif float* qkvp = qkv.as_fp32(); const float* cos_p = freqs_cos_.as_fp32(); const float* sin_p = freqs_sin_.as_fp32(); for (size_t h = 0; h < n_heads; ++h) { size_t q_off = h * head_dim_; size_t k_off = d_model + h * head_dim_; for (size_t i = 0; i < seq_len; ++i) { size_t pos = offset + i; if (pos >= max_seq_len_) { if (yarn_scale_factor_ > 1.0f) { pos = pos % max_seq_len_; } else { pos = max_seq_len_ - 1; } } for (size_t d = 0; d < half_dim; ++d) { float c = cos_p[pos * half_dim + d]; float s = sin_p[pos * half_dim + d]; size_t qi = i * 3 * d_model + q_off + d; size_t qi2 = i * 3 * d_model + q_off + half_dim + d; float q0 = qkvp[qi]; float q1 = qkvp[qi2]; qkvp[qi] = q0 * c - q1 * s; qkvp[qi2] = q0 * s + q1 * c; size_t ki = i * 3 * d_model + k_off + d; size_t ki2 = i * 3 * d_model + k_off + half_dim + d; float k0 = qkvp[ki]; float k1 = qkvp[ki2]; qkvp[ki] = k0 * c - k1 * s; qkvp[ki2] = k0 * s + k1 * c; } } } } void RoPE::apply_single(Tensor& x, size_t seq_len, size_t n_heads, size_t offset) const { size_t half_dim = head_dim_ / 2; size_t stride = n_heads * head_dim_; #ifdef USE_CUDA if (CudaContext::instance().is_available() && x.is_on_gpu()) { launch_rope_single(x.as_gpu_fp32(), freqs_cos_.as_gpu_fp32(), freqs_sin_.as_gpu_fp32(), seq_len, n_heads, stride, head_dim_, offset, CudaContext::instance().stream()); x.gpu_dirty_ = true; return; } #endif float* xp = x.as_fp32(); const float* cos_p = freqs_cos_.as_fp32(); const float* sin_p = freqs_sin_.as_fp32(); for (size_t h = 0; h < n_heads; ++h) { size_t h_off = h * head_dim_; for (size_t i = 0; i < seq_len; ++i) { size_t pos = offset + i; if (pos >= max_seq_len_) { pos = yarn_scale_factor_ > 1.0f ? pos % max_seq_len_ : max_seq_len_ - 1; } for (size_t d = 0; d < half_dim; ++d) { float c = cos_p[pos * half_dim + d]; float s = sin_p[pos * half_dim + d]; size_t idx0 = i * stride + h_off + d; size_t idx1 = i * stride + h_off + half_dim + d; float x0 = xp[idx0]; float x1 = xp[idx1]; xp[idx0] = x0 * c - x1 * s; xp[idx1] = x0 * s + x1 * c; } } } } void RoPE::set_yarn_scale(float scale_factor) { if (scale_factor <= 1.0f) return; if (scale_factor > 100.0f) { std::cerr << "[YaRN WARNING] Extreme scale_factor=" << scale_factor << ", results may be unreliable" << std::endl; } yarn_scale_factor_ = scale_factor; float* cos_p = freqs_cos_.as_fp32(); float* sin_p = freqs_sin_.as_fp32(); float base = 10000.0f; size_t half_dim = head_dim_ / 2; for (size_t pos = 0; pos < max_seq_len_; ++pos) { for (size_t d = 0; d < half_dim; ++d) { float freq = 1.0f / std::pow(base, static_cast(2 * d) / static_cast(head_dim_)); float scaled_freq = freq / scale_factor; float angle = static_cast(pos) * scaled_freq; cos_p[pos * half_dim + d] = std::cos(angle); sin_p[pos * half_dim + d] = std::sin(angle); } } #ifdef USE_CUDA if (CudaContext::instance().is_available()) { freqs_cos_.to_gpu(); freqs_sin_.to_gpu(); } #endif std::cerr << "[YaRN] Applied scale_factor=" << scale_factor << ", temp_scale=" << (std::sqrt(std::log(scale_factor)) + 1.0f) << std::endl; } #ifdef USE_CUDA __global__ void kernel_rope_impl(float* qkv, const float* cos_table, const float* sin_table, size_t seq_len, size_t n_heads, size_t d_model, size_t head_dim, size_t half_dim, size_t offset) { size_t idx = blockIdx.x * blockDim.x + threadIdx.x; size_t total = seq_len * n_heads * half_dim; if (idx >= total) return; size_t d = idx % half_dim; size_t h = (idx / half_dim) % n_heads; size_t i = idx / (n_heads * half_dim); size_t pos = offset + i; float c = cos_table[pos * half_dim + d]; float s = sin_table[pos * half_dim + d]; size_t q_off = h * head_dim; size_t k_off = d_model + h * head_dim; size_t qi = i * 3 * d_model + q_off + d; size_t qi2 = i * 3 * d_model + q_off + half_dim + d; float q0 = qkv[qi]; float q1 = qkv[qi2]; qkv[qi] = q0 * c - q1 * s; qkv[qi2] = q0 * s + q1 * c; size_t ki = i * 3 * d_model + k_off + d; size_t ki2 = i * 3 * d_model + k_off + half_dim + d; float k0 = qkv[ki]; float k1 = qkv[ki2]; qkv[ki] = k0 * c - k1 * s; qkv[ki2] = k0 * s + k1 * c; } void launch_rope(float* qkv, const float* cos_table, const float* sin_table, size_t seq_len, size_t n_heads, size_t d_model, size_t head_dim, size_t offset, cudaStream_t stream) { size_t half_dim = head_dim / 2; size_t total = seq_len * n_heads * half_dim; int block = 256; int grid = (static_cast(total) + block - 1) / block; kernel_rope_impl<<>>(qkv, cos_table, sin_table, seq_len, n_heads, d_model, head_dim, half_dim, offset); } __global__ void kernel_rope_single_impl(float* data, const float* cos_table, const float* sin_table, size_t seq_len, size_t n_heads, size_t stride, size_t head_dim, size_t half_dim, size_t offset) { size_t idx = blockIdx.x * blockDim.x + threadIdx.x; size_t total = seq_len * n_heads * half_dim; if (idx >= total) return; size_t d = idx % half_dim; size_t h = (idx / half_dim) % n_heads; size_t i = idx / (n_heads * half_dim); size_t pos = offset + i; float c = cos_table[pos * half_dim + d]; float s = sin_table[pos * half_dim + d]; size_t h_off = h * head_dim; size_t idx0 = i * stride + h_off + d; size_t idx1 = i * stride + h_off + half_dim + d; float x0 = data[idx0]; float x1 = data[idx1]; data[idx0] = x0 * c - x1 * s; data[idx1] = x0 * s + x1 * c; } void launch_rope_single(float* data, const float* cos_table, const float* sin_table, size_t seq_len, size_t n_heads, size_t stride, size_t head_dim, size_t offset, cudaStream_t stream) { size_t half_dim = head_dim / 2; size_t total = seq_len * n_heads * half_dim; int block = 256; int grid = (static_cast(total) + block - 1) / block; kernel_rope_single_impl<<>>(data, cos_table, sin_table, seq_len, n_heads, stride, head_dim, half_dim, offset); } #endif } // namespace neuroflow