问题描述
我正在GPU(CUDA)上进行物理仿真,并在标准图形卡上的有限可用内存中苦苦挣扎。
问题如下:
我有一个巨大的二进制掩码(> 30 GB),可以用作查找表。为了评估特定变量的有效性,我从变量属性中生成了一个索引,并对照查找表进行检查。在GPU上同时为数百万个变量并行完成此操作(仅需要读取访问权限)。
为了最小化此二进制掩码的大小以使其适合GPU内存,我正在寻找压缩技术,该技术仍可以通过对基础数据建立索引来实现快速访问(最好由负责所有事务的透明容器类)。由于掩码本身包含多个重复的单个位,因此我也希望可以实现较高的压缩率。
所以我的问题是:
nvidia的CUDA实施中是否已有已知方法? 还有其他默认的C ++库可以做到这一点吗?
解决方法
行程编码
我不知道有哪个库可以为您执行此操作,但是我可以为您提供有关如何执行此操作的想法。由于您的掩码包含同一位的许多重复,因此一种合适的方法是运行长度编码(RLE)。这个想法是,您可以对字节及其长度进行编码,而不是对单个字节进行编码:
aaabbbababaaaaaaaa -> 3a,3b,1a,1b,6a
有许多方法可以在实践中实现。我正在研究体素模型压缩,最适合我的方法是使用字节0x00
和0xff
作为转义序列。因此[0x00,N]
编码N个零字节,[0xff,N]
编码N个填充字节。其余字节保持未压缩状态。另外,您也可以只使用zlib进行DEFLATE压缩,我敢肯定也有GPU实现。
获得O(1)随机访问权限
任何类型的压缩技术都存在的问题是,它将数据缩减为可变大小,从而使得无法进行随机访问。为了解决这个问题,您必须将数据压缩为1024个字节。然后,您可以存储指向每个块开头的指针表,以允许您随机访问。
一个明显的问题是,一次只能压缩一个块,而每次访问一个不同的块时,也需要对其进行解压缩。这可能非常昂贵。
确定O(log n)随机访问
另一种技术是将数据压缩为八进制树。较高级别的字节的八位表示较低的八个字节中的哪个存在,哪些不存在。
0 0 1 1 // Higher-level bitmask representing
/ | | \ // which bytes exist.
0000.0000 0000.0000 0010.1111 1111.1111 // Lower-level bytes.
在这里,1
代表现有子树,0
代表丢失的子树。
我们可以将该树优化为:
0 0 1 1
| \
0010.1111 1111.1111
较高级别的零位表示较低级别的全零数据,因此我们可以优化那些较低级别的数据。通过将数据安排在这样的树中,我们可以以O(log n)复杂度随机访问任何位。这种技术的优点是我们有很多相邻的1或0,它们将被优化掉并在更高的级别上变成单个位。
请注意,我们还可以优化全一的子树。为此,我们在更高级别使用0x00
的掩码。 0x00
掩码自然不会出现,因为它会被优化为更高级别的单个零位。因此,我们可以为其赋予一些特殊含义。