【发布时间】:2020-12-16 10:12:15
【问题描述】:
我正在 Kotlin 中构建一个深度神经网络(我知道 Python 会更好,但我必须在 Kotlin 中这样做)。
为了训练网络,我需要来自MNIST database 的大量数据,这意味着我需要从一个 IDX 格式的文件中读取大约 60,000 张图像并将它们存储起来以供同时使用。
每个图像由 784 个字节组成。所以总大小是: 784*60,000 = 47,040,000 = ~47 MB 的训练数据。 这不算多,因为我在 8GB RAM 环境中运行 JVM。
读取图像后,我需要将其转换为KMatrix,这是一种用于矩阵数学运算的自定义数据结构。在KMatrix 的引擎盖下有一个Array<Array<Double>>。
我需要一个结构来一次存储所有图像,所以我目前使用的是List<KMatrix>,它基本上转换为List<Array<Array<Double>>>
问题在于,在构建 List<KMatrix> 时,垃圾收集器会耗尽内存,从而启动 OutOfMemoryException: GC overhead limit exceeded。
我想知道问题是我正在使用 哪些 数据结构(即我应该使用 ArrayList 而不是 Array 吗?)或者可能是 如何 我正在构建整件事(即我需要做一些优化工作)。
如果需要,我会尽快提供代码。
感谢您的帮助。
【问题讨论】:
-
通过将
Array<Array<Double>>替换为Array<DoubleArray>,您将大大节省内存和性能。更进一步,您可以使用一维DoubleArray并使用[row * width + column]获取您的元素。更进一步,您可以考虑使用DoubleBuffer而不是DoubleArray。 -
我认为这正是我想要的。非常感谢!
-
不客气。关于 DoubleBuffer,您需要使用
ByteBuffer.allocateDirect(8 * size).asDoubleBuffer()而不是DoubleBuffer.allocate(size)。直接缓冲区表现更好。 -
转换
Array<Double>→DoubleArray几乎总是值得的,因为后者将值存储为原语,避免了前者需要的所有装箱的Double对象。 (对于其他原始数组类型也是如此。)——然而,将这些数组转换成一个带有手动索引的单个数组会节省很多,而且不太可能证明额外的复杂性是合理的。 -
@gidds 是的,你可能是对的,但由于在深度学习中节省每一毫秒都是值得的,所以无论如何我都在尝试实现它。此外,在我的具体情况下,使用 1D DoubleArray 有一些非常简单的操作 - 例如将任何给定的 (Double) -> (Double) lambda 应用于 KMatrix 的每个元素。这不是一个巨大的进步,但仍然是双赢。
标签: kotlin data-structures memory-leaks garbage-collection out-of-memory