Repository navigation
Reduce over scalar costs when picking the best particle - #151
Conversation
GPU `minimum` over whole particles/gbests stages each element in shared memory, so large-dimension positions overflow it and the reduction launches with zero threads. Pick the best via `argmin` over costs instead, mapping NaN costs to typemax so they never win. This covers the sync kernel's block reduction over SPSOGBest as well as the particle reductions in init, the async/CPU solvers, and ODE parameter estimation. Adds a 128-dimension case to the dimension-independence GPU test.
sol.objective is prob.f recomputed on the host, so it can differ from the device-computed best_cost by an ulp on CUDA (also seen on main). Check the copied position exactly and the cost approximately.
|
@utkarsh530 Please take a look |
… fix Pins ParallelParticleSwarms to 73dee70c from SciML/ParallelParticleSwarms.jl#151. On the GPU, minimum() over whole SPSOParticle/SPSOGBest structs staged each element in shared memory, so the 86-dimensional B5 particles overflowed it and the kernels launched with zero threads, leaving every GPU swarm run at best = Inf. The PR reduces over the scalar costs instead. Move the pin to the merged commit or a release once SciML#151 is merged.
|
Thanks for this fix. Reducing cost/index candidates instead of complete particle records is the right direction for the shared-memory issue, and the CUDA CI run passed. Reviewing head
Two follow-ups:
Validation here was isolated Julia helper tests plus host replay of the block comparisons; I did not run GPU kernels locally. |
…r-reduce # Conflicts: # test/gpu.jl
…zers - `_best_particle` reduces over (cost, index) with `isless`, so NaN ranks after every number including Inf ([NaN, Inf] now picks Inf), ties go to the lowest index, and an all-NaN population yields the first particle. The CPU path is a plain loop over the same ordering. - The sync block kernel compares with `isless` and pads with NaN, so a NaN particle no longer displaces a finite one within a block. - Tests: helper regressions for SPSOParticle and SPSOGBest ([NaN, Inf], its reverse, mixed finite/NaN, -Inf, all NaN, ties); a NaN-objective solve for every kernel variant; global_update = false (including a ragged 257-particle population) in the D = 128 test; the brute-force check accepts any tied minimizer and adds a tie-heavy objective.
Problem
minimum(gpu_particles)andminimum(block_particles)reduce over wholeSPSOParticle/SPSOGBeststructs. On GPU the reduction stages each element in shared memory, so large-dimension positions overflow it and the kernel launches with zero threads.Fix
Add
_best_particle, which runsargminover the scalar costs and then copies back only the winning element. NaN costs map totypemax, so they never win. Without this,argmintreats NaN as the smallest value, and the oldisless-basedminlet a NaN win depending on its position.It replaces every
minimumreduction insrc/:ParallelSyncPSOKernelblock reduction overSPSOGBest(lowerlevel_solve.jl)ParallelPSOKernelsolversinit.jl)ode_pso.jl)On plain
Arrays (the CPU backend), it usesargmin(f, ps)directly, so it allocates nothing.Tests
D = 128case to the "reduction is dimension-independent" test intest/gpu.jl.sol.objective(prob.frecomputed on the host) to the GPU-computedbest_costwith==, which failed by 1 ulp on CUDA, including onmain. It now checks the winning position exactly and the cost with≈.