0

我正在使用带有 CUDA 8.0 的 JCuda 版本 0.8.0RC 在 GTX1080 GPU 上进行矩阵乘法。我将两个矩阵 A 和 B 以行主向量形式加载到设备中,并从设备中读取乘积矩阵。但我发现我的设备内存比我预期的要早用完。例如,如果矩阵 A 的尺寸为 100000 * 5000 = 5 亿个条目 = 2GB 的浮点值,则:

cuMemAlloc(MatrixA, 100000 * 5000 * Sizeof.FLOAT); 

工作正常。但是,如果我将行数或行数从 100000 增加到 110000,则在此调用中会出现以下错误(这是在矩阵 B 和 C 的内存分配之前发生的,因此这些不是问题的一部分):

Exception in thread "main" jcuda.CudaException: CUDA_ERROR_OUT_OF_MEMORY
at jcuda.driver.JCudaDriver.checkResult(JCudaDriver.java:344)
at jcuda.driver.JCudaDriver.cuMemAlloc(JCudaDriver.java:3714)
at JCudaMatrixMultiply.main(JCudaMatrixMultiply.java:84) (my code)

问题是在设备上分配这种大小的矩阵应该只需要大约 2.2GB,而 GTX1080 有 8GB 内存,所以我不明白为什么我的内存不足。有人对此有任何想法吗?确实,我将 JCuda 0.8.0RC 与 CUDA 8 的发布版本一起使用,但我尝试下载 CUDA 8 (8.0.27) 的 RC 版本以与 JCuda 0.8.0RC 一起使用,但在使其工作时遇到了一些问题. 但是,如果版本兼容性可能是问题,我可以再试一次。

当然,100000 * 5000 的矩阵非常大,在我的神经网络项目中我暂时不需要使用更大的矩阵,但我想确信我可以在这个新的上使用所有 8GB 内存卡片。谢谢你的帮助。

4

1 回答 1

2

tl;博士:

打电话时

cuMemAlloc(MatrixA, (long)110000 * 5000 * Sizeof.FLOAT); 
//                     ^ cast to long here

或者

cuMemAlloc(MatrixA, 110000L * 5000 * Sizeof.FLOAT); 
//                        ^ use the "long" literal suffix here

它应该工作。


的最后一个参数cuMemAlloc是类型size_t。这是“任意”大小的特定于实现的无符号整数类型。Java 中最接近的原始类型是long. 通常,size_tCUDA 中的每个都映射到longJCuda 中。在这种情况下,Javalong被作为 a 传递jlong到 JNI 层,这只是size_t为实际的本机调用而转换。

(Java 中缺少无符号类型和 C 中奇数过多的整数类型仍然会导致问题。有时,C 类型和 Java 类型不匹配。但只要分配不大于 900 万兆兆字节(!),long这里应该没问题...)

评论havogt导致正确的轨道。这里发生确实是整数溢出:实际值的计算

110000 * 5000 * Sizeof.FLOAT = 2200000000

默认情况下使用intJava 中的类型完成,这就是发生溢出的地方:2200000000 大于Integer.MAX_VALUE. 结果将是一个负值。当这在 JNI 层中被转换为(无符号)size_t值时,它将变成一个可笑的大正值,这显然会导致错误。

在使用long值进行计算时,通过显式转换long或将L后缀附加到文字之一,该值将作为正确long值 2200000000 传递给 CUDA。

于 2016-11-11T17:40:51.780 回答