finish ItakuraSaitoDistanceLoss #93

This commit is contained in:
uucoco 2025-12-10 19:14:44 +08:00
parent 10eed82956
commit 46e7998cae
4 changed files with 316 additions and 0 deletions

View File

@ -0,0 +1,85 @@
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
cuda_source = """
#include <torch/extension.h>
#include <cuda_runtime.h>
__global__ void itakura_saito_kernel(
const float* __restrict__ input,
const float* __restrict__ target,
float* __restrict__ output,
int n,
float eps
) {
extern __shared__ float sdata[];
int tid = threadIdx.x;
int idx = blockIdx.x * blockDim.x + threadIdx.x;
float local_sum = 0.0f;
for (int i = idx; i < n; i += blockDim.x * gridDim.x) {
float x = input[i];
float y = target[i];
float ratio = y / (x + eps);
float term = ratio - logf(ratio + eps) - 1.0f;
local_sum += term;
}
sdata[tid] = local_sum;
__syncthreads();
for (int s = blockDim.x / 2; s > 0; s >>= 1) {
if (tid < s) {
sdata[tid] += sdata[tid + s];
}
__syncthreads();
}
if (tid == 0) {
atomicAdd(output, sdata[0]);
}
}
torch::Tensor itakura_saito_cuda(torch::Tensor input, torch::Tensor target, float eps) {
int n = input.numel();
auto output = at::zeros({1}, input.options());
int threads = 256;
int blocks = 128;
int shared_mem = threads * sizeof(float);
itakura_saito_kernel<<<blocks, threads, shared_mem>>>(
input.data_ptr<float>(),
target.data_ptr<float>(),
output.data_ptr<float>(),
n,
eps
);
return output / n;
}
"""
cpp_source = """
torch::Tensor itakura_saito_cuda(torch::Tensor input, torch::Tensor target, float eps);
"""
itakura_saito_loss = load_inline(
name="itakura_saito_loss",
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=["itakura_saito_cuda"],
verbose=False
)
class ModelNew(nn.Module):
def __init__(self, eps=1e-8):
super(ModelNew, self).__init__()
self.eps = eps
def forward(self, input, target):
return itakura_saito_loss.itakura_saito_cuda(input, target, self.eps)

View File

@ -0,0 +1,23 @@
import torch
import torch.nn as nn
class Model(nn.Module):
def __init__(self, eps=1e-8):
super(Model, self).__init__()
self.eps = eps
def forward(self, input, target):
ratio = target / (input + self.eps)
loss = ratio - torch.log(ratio + self.eps) - 1.0
return loss.mean()
batch_size = 32
input_dim = 1024
def get_inputs():
input = torch.abs(torch.randn(batch_size, input_dim, requires_grad=True)) + 0.1
target = torch.abs(torch.randn(batch_size, input_dim)) + 0.1
return [input, target]
def get_init_inputs():
return [1e-8]

131
S1/uucoco_#93/prompt.txt Normal file
View File

@ -0,0 +1,131 @@
You write custom CUDA kernels to replace the pytorch operators in the given GeGLU architecture to get speedups.
You have complete freedom to choose the set of operators you want to replace. You may make the decision to replace some operators with custom CUDA kernels and leave others unchanged. You may replace multiple operators with custom implementations, consider operator fusion opportunities (combining multiple operators into a single kernel, for example, combining chunk+gelu+elementwise_mul), or algorithmic changes (such as optimized memory access patterns). You are only limited by your imagination.
Technologies Used in This Code
Core Libraries & Frameworks
PyTorch: Deep learning framework
CUDA: NVIDIA's parallel computing platform for GPU acceleration
C++: For high-performance kernel implementation
PyTorch Specific Components
torch.nn.Module: Base class for neural network modules
torch.utils.cpp_extension.load_inline: For inline compilation of CUDA/C++ extensions
PyTorch Tensors: Multi-dimensional arrays with automatic differentiation
Tensor.numel(): Method to get total number of elements
CUDA/C++ Implementation Details
CUDA Kernels: Custom GPU kernel (itakura_saito_kernel)
CUDA Math Functions: logf() for logarithmic computations
Parallel Reduction: Tree-based reduction using shared memory
Shared Memory: Using __shared__ for inter-thread communication
Atomic Operations: atomicAdd for thread-safe global updates
Grid-Stride Loops: Efficient memory access pattern
Mathematical Components
Itakura-Saito Distance: Spectral distance measure for signals/spectra
Ratio Computation: y/(x+eps) ratio calculation
Logarithmic Term: log(ratio+eps) component
Three-Term Formula: ratio - log(ratio) - 1 formulation
Numerical Stability: Epsilon (eps) to prevent division by zero and log(0)
Signal Processing/Spectral Analysis Components
Spectral Distance: Originally designed for power spectra comparison
Scale Invariance: Property of Itakura-Saito distance
Non-Negative Inputs: Typically used with power spectra (non-negative values)
Element-Wise Computation: Independent computation across frequency bins
Optimization Techniques
Shared Memory Reduction: Parallel tree reduction within thread blocks
Grid-Stride Loops: Efficient handling of arbitrary tensor sizes
Numerical Stability: Dual epsilon usage for division and log operations
Fused Computation: Complete distance calculation in single kernel
Element-Wise Parallelism: Massive parallelism across all tensor elements
Performance Features
Massive Parallelization: GPU acceleration for distance computation
Memory Efficiency: Shared memory for intermediate reduction results
Atomic Accumulation: Safe parallel sum across thread blocks
Scalable Design: Efficient for any tensor shape/size
Mean Normalization: Final division by total number of elements
Unique Implementation Aspects
Dual Epsilon Protection: Prevents both division by zero and log(0)
Ratio-Based Computation: Core of Itakura-Saito formulation
Element-Wise Metric: Unlike matrix-based distances, operates element-wise
Signal Processing Focus: Specialized for spectral/power distribution comparison
Scale Invariant: Important property preserved in implementation
Applications & Use Cases
Speech Processing: Originally for speech spectrum comparison
Audio Signal Analysis: Power spectrum distance measurement
Non-Negative Matrix Factorization: Common divergence measure in NMF
Spectral Data: Suitable for any non-negative spectral/power data
Numerical Considerations
Non-Negative Inputs: Expects non-negative values (typical for spectra)
Epsilon Selection: Small but non-zero to ensure numerical stability
Ratio Stability: Protected against both numerator and denominator extremes
Mean Computation: Averages across all elements (not batch mean)
Here's an example to show you the syntax of inline embedding custom CUDA operators in torch: The example given architecture is:
import torch
import torch.nn as nn
class Model(nn.Module):
def __init__(self, eps=1e-8):
super(Model, self).__init__()
self.eps = eps
def forward(self, input, target):
ratio = target / (input + self.eps)
loss = ratio - torch.log(ratio + self.eps) - 1.0
return loss.mean()
batch_size = 32
input_dim = 1024
def get_inputs():
input = torch.abs(torch.randn(batch_size, input_dim, requires_grad=True)) + 0.1
target = torch.abs(torch.randn(batch_size, input_dim)) + 0.1
return [input, target]
def get_init_inputs():
return [1e-8]

77
S1/uucoco_#93/run_code.py Normal file
View File

@ -0,0 +1,77 @@
###########################################################
# 性能和精度验证程序
###########################################################
import torch
import torch.nn as nn
import time
from ItakuraSaitoDistanceLoss_torch import Model, get_inputs, get_init_inputs
from ItakuraSaitoDistanceLoss_cuda import ModelNew
def run_benchmark():
# 检查 CUDA 是否可用
if not torch.cuda.is_available():
print("CUDA 不可用,请确保您有可用的 NVIDIA GPU 并已正确安装 PyTorch CUDA 版本。")
return
else:
device = torch.device("cuda")
# 初始化模型
init_inputs = get_init_inputs()
init_inputs = [
x.cuda(device=device) if isinstance(x, torch.Tensor) else x for x in init_inputs
]
inputs = get_inputs()
inputs = [
x.cuda(device=device) if isinstance(x, torch.Tensor) else x for x in inputs
]
torch_model = Model(*init_inputs).cuda()
cuda_model = ModelNew(*init_inputs).cuda()
torch_model.eval()
cuda_model.eval()
print("-------------------- 精度对齐验证 --------------------")
with torch.no_grad():
output_torch = torch_model(*inputs)
output_cuda = cuda_model(*inputs)
precision_flag = torch.allclose(output_torch, output_cuda, rtol=1e-03)
if precision_flag:
print("✅ 精度对齐:两个模型的输出结果非常接近。")
else:
print("❌ 精度不一致!")
print("\n-------------------- 性能加速比测试 --------------------")
num_iterations = 100
# PyTorch 模型计时
torch.cuda.synchronize()
start_time = time.time()
for _ in range(num_iterations):
_ = torch_model(*inputs)
torch.cuda.synchronize()
torch_time = (time.time() - start_time) / num_iterations
# 自定义 CUDA 内核计时
torch.cuda.synchronize()
start_time = time.time()
for _ in range(num_iterations):
_ = cuda_model(*inputs)
torch.cuda.synchronize()
cuda_time = (time.time() - start_time) / num_iterations
print(f"PyTorch torch.relu 平均执行时间: {torch_time:.6f}")
print(f"自定义 CUDA 内核 平均执行时间: {cuda_time:.6f}")
speedup = 0
if cuda_time > 0:
speedup = torch_time / cuda_time
print(f"加速比 (Speedup): {speedup:.2f}x")
else:
print("CUDA 内核执行时间为0无法计算加速比。")
return precision_flag, speedup
if __name__ == "__main__":
precision_flag, speedup = run_benchmark()