我正在尝试解决 GPU(CUDA)上的一些无约束非线性优化问题。
目标函数是一个光滑的非线性函数,它的梯度解析计算相对便宜,所以我不需要数值逼近。
我想用大多数 fp32 数学运算(出于各种原因)来解决这个问题,那么哪种非线性优化方法对舍入错误更鲁棒,同时具有良好的性能?(例如共轭梯度/准牛顿/信任区域),有没有人在 GPU 上尝试过 BFGS,效果很好?
顺便说一句,如果需要,Hessian 在我的情况下相对较小(通常<64x64),但我需要同时解决数千个这样的小规模优化问题。
我正在尝试解决 GPU(CUDA)上的一些无约束非线性优化问题。
目标函数是一个光滑的非线性函数,它的梯度解析计算相对便宜,所以我不需要数值逼近。
我想用大多数 fp32 数学运算(出于各种原因)来解决这个问题,那么哪种非线性优化方法对舍入错误更鲁棒,同时具有良好的性能?(例如共轭梯度/准牛顿/信任区域),有没有人在 GPU 上尝试过 BFGS,效果很好?
顺便说一句,如果需要,Hessian 在我的情况下相对较小(通常<64x64),但我需要同时解决数千个这样的小规模优化问题。
我在 GPU 上实现了各种各样的非线性求解器,包括 LBFGS、Barzilai Borwein 梯度下降和非线性共轭梯度。
为此,戴元的非线性共轭梯度一直是最有效的。一般来说,非线性共轭梯度的其他版本可能更有效(例如 CG-DESCENT),但也可能更难以实现。
LBFGS 通常是一个非常可靠的选择,除非你真的被内存所束缚,否则它可能是最好的起点。
但是,共轭梯度和 BFGS 都需要线搜索,这就是 fp32 成为问题的地方。我建议使用此处建议的近似 Wolfe 条件,而不是使用标准 Wolfe 条件进行线搜索。这篇论文有点涉及,但重要的是方程 4.1。本质上,它们明确地介绍了您可以计算函数的精度。
GPU 的注意事项:
你有很多小问题,这与我的一个大问题的用例略有不同。如果您可以并行化函数和梯度评估以使用块中的所有线程,请考虑为每个 GPU 块(或扭曲)运行 1 个问题。这样,如果不同的问题需要不同的迭代次数,这不是问题。
如果这不是一个选项,我会选择 LBFGS 求解器。如果您的函数表现良好,您可能只需使用 1 的步长(避免线搜索)并在固定次数的迭代中运行所有问题即可。
我建议您使用 Levenberg Marquardt(一种信任区域变体),因为它已在许多实际应用中使用,并且表现出非常好的速度与准确性性能。此外,对于 GPU,还有一些库(例如 cuLM https://github.com/zitmen/cuLM),您可以尝试一下。如果他们不做这项工作,那么您可以实施大量资源。实施 LM 一点也不难。您应该只注意最小化 GPU 通信。简要了解一下:
也许模拟退火程序可以更好地处理舍入误差(并且很容易并行化)。
您从搜索区域的粗略网格和初始“温度”参数开始
在每一步,您都会计算可能的解点(也可以接受非解点,其概率与温度成反比)
然后仅保留该步骤的解决方案并提高温度,从而为下一次迭代提供更细粒度的网格
这样做直到温度 < 给定的精度限制/阈值