通过 ArrayFire 在 GPU 上使用 Julia 编写代码的最佳方式
The best way to write code in Julia working on GPU's via ArrayFire
在 Julia 中,我主要看到当我在矩阵上工作时加速和优化代码,es 更好,例如
-按列而不是按行工作,这是 Julia 存储矩阵的方式。
-On 循环可以使用 @inbounds
和 @simd
宏
-欢迎您推荐任何函数、宏或方法:D
但是当我使用带有存储在 GPU 上的矩阵的 ArrayFire 包时,上面的示例似乎不起作用,CPU 和 GPU 中的类似代码似乎不利于运行多的 GPU有些情况下比较慢,我觉得不应该是这样的,我觉得问题出在代码的写法上。欢迎任何帮助
GPU 计算应尽可能在优化的 GPU 内核上进行。索引 GPU 数组是一个小内核,它将一个值复制回 CPU。这对性能来说真的很糟糕,所以你几乎不应该索引 GPUArray 除非你必须这样做(这对任何实现都是如此!这只是一个硬件问题!)
因此,与其为 GPU 编写循环代码,不如编写广播 ("vectorized") 代码。使用 v0.6 broadcast changes, broadcasted operations are nearly as efficient as loops anyways (unless you hit this bug),因此没有理由在通用代码中避免使用它们。然而,有些情况下广播比循环更快,GPU 就是一个大案例。
让我解释一下原因。当你执行代码时:
@. A = B*C + D*E
它降低到
A .= B.*C .+ D.*E
然后下降到:
broadcast!((b,c,d,e)->b*c + d*e,A,B,C,D,E)
请注意,这里有一个用于整个广播的融合匿名函数。对于 GPUArrays,这将被覆盖,以便自动创建单个 GPU 内核来逐元素执行此融合操作。因此,只需要一个 GPU 内核即可完成整个操作!请注意,这比 R/Python/MATLAB 进行 GPU 计算的方式更有效,因为这些矢量化形式具有临时性,并且在这里需要 4 个内核,但它没有临时数组并且是单个内核,这几乎就是如果您自己编写内核,您就会编写它。因此,如果您利用广播,那么您的 GPU 计算将会很快。
在 Julia 中,我主要看到当我在矩阵上工作时加速和优化代码,es 更好,例如
-按列而不是按行工作,这是 Julia 存储矩阵的方式。
-On 循环可以使用 @inbounds
和 @simd
宏
-欢迎您推荐任何函数、宏或方法:D
但是当我使用带有存储在 GPU 上的矩阵的 ArrayFire 包时,上面的示例似乎不起作用,CPU 和 GPU 中的类似代码似乎不利于运行多的 GPU有些情况下比较慢,我觉得不应该是这样的,我觉得问题出在代码的写法上。欢迎任何帮助
GPU 计算应尽可能在优化的 GPU 内核上进行。索引 GPU 数组是一个小内核,它将一个值复制回 CPU。这对性能来说真的很糟糕,所以你几乎不应该索引 GPUArray 除非你必须这样做(这对任何实现都是如此!这只是一个硬件问题!)
因此,与其为 GPU 编写循环代码,不如编写广播 ("vectorized") 代码。使用 v0.6 broadcast changes, broadcasted operations are nearly as efficient as loops anyways (unless you hit this bug),因此没有理由在通用代码中避免使用它们。然而,有些情况下广播比循环更快,GPU 就是一个大案例。
让我解释一下原因。当你执行代码时:
@. A = B*C + D*E
它降低到
A .= B.*C .+ D.*E
然后下降到:
broadcast!((b,c,d,e)->b*c + d*e,A,B,C,D,E)
请注意,这里有一个用于整个广播的融合匿名函数。对于 GPUArrays,这将被覆盖,以便自动创建单个 GPU 内核来逐元素执行此融合操作。因此,只需要一个 GPU 内核即可完成整个操作!请注意,这比 R/Python/MATLAB 进行 GPU 计算的方式更有效,因为这些矢量化形式具有临时性,并且在这里需要 4 个内核,但它没有临时数组并且是单个内核,这几乎就是如果您自己编写内核,您就会编写它。因此,如果您利用广播,那么您的 GPU 计算将会很快。