// ═══════════════════════════════════════════════════════════════════════════ // CUDA kernels for GPU-resident Integrated Gradients (IG). // // Sundararajan et al. (2017). Attributions are obtained by integrating the // model's gradient along the straight-line path baseline -> input: // // attribution_i = (x_i - baseline_i) * (1/M) * sum_{k=0..M-1} d F/d x_i // evaluated at the k-th // interpolation point. // // These kernels handle the two per-step GPU primitives: // // 1. `interpolate_input` : builds x(alpha) = baseline + alpha * (input - baseline) // 2. `perturb_dimension` : copies a buffer and perturbs a single coordinate // (used to build x_plus / x_minus for central // finite differences). // // All kernels use a 1-D grid-stride layout with 256 threads per block. // Launch config: blocks = ceil(n / 256), block_dim = 256, shared_mem = 0. // Deterministic — no atomicAdd, no warp-level reductions, no randomness. // ═══════════════════════════════════════════════════════════════════════════ // Build: output[i] = baseline[i] + alpha * diff[i] (element-wise) // // Launch: grid_dim = (ceil(n / 256), 1, 1), block_dim = (256, 1, 1). extern "C" __global__ void interpolate_input( const float* __restrict__ baseline, const float* __restrict__ diff, float* __restrict__ output, float alpha, int n) { int i = blockIdx.x * blockDim.x + threadIdx.x; if (i < n) { output[i] = baseline[i] + alpha * diff[i]; } } // Copy src to dst, then apply dst[dim] += delta. // // The full copy is performed on every thread (rather than a targeted single // write) so dst is always a complete, coherent snapshot of src with exactly // one perturbed coordinate. This avoids needing a separate cudaMemcpy before // the perturbation and keeps the operation a single kernel launch per probe. // // Launch: grid_dim = (ceil(n / 256), 1, 1), block_dim = (256, 1, 1). extern "C" __global__ void perturb_dimension( const float* __restrict__ src, float* __restrict__ dst, int dim, float delta, int n) { int i = blockIdx.x * blockDim.x + threadIdx.x; if (i < n) { float val = src[i]; if (i == dim) { val += delta; } dst[i] = val; } }