neuroflow-cpp / src /rope.cpp
cwenzi's picture
Upload folder using huggingface_hub
26d5b81 verified
Raw
History Blame Contribute Delete
8.98 kB
#include "neuroflow/rope.hpp"
#include <cmath>
#include <iostream>
#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<float>(2 * d) / static_cast<float>(head_dim));
float angle = static_cast<float>(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<float>(2 * d) / static_cast<float>(head_dim_));
float scaled_freq = freq / scale_factor;
float angle = static_cast<float>(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<int>(total) + block - 1) / block;
kernel_rope_impl<<<grid, block, 0, stream>>>(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<int>(total) + block - 1) / block;
kernel_rope_single_impl<<<grid, block, 0, stream>>>(data, cos_table, sin_table,
seq_len, n_heads, stride, head_dim, half_dim, offset);
}
#endif
} // namespace neuroflow