Kotlin Array vs ArrayList vs List用于存储大量数据
Kotlin's Array vs ArrayList vs List for storing large amounts of data
我正在 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 而不是数组吗?)或者 如何 我正在构建整个东西(即我需要做一些优化工作)。
如果需要,我会尽快放上代码。
感谢您的帮助。
Self-answer 总结解决方案(感谢@Tenfour04 和@gidds 的回答)
正如@Tenfour04 所述,对于 KMatrix
:
,您基本上有三种替代 Array<Array<Double>>
的方法
- 一个
Array<DoubleArray>
与原始逻辑保持相同的逻辑,但节省了大量内存并提高了性能;
- a 1-Dimensional
DoubleArray
节省了一些额外的内存和性能,但增加了数组的 index-mapping 的复杂性(矩阵的 [i;j] 元素由数组的 [i * w + j] 元素给出),正如@gidds 指出的那样,这可能不值得;
- 用
ByteBuffer.allocateDirect(8 * size).asDoubleBuffer()
创建的一维DoubleBuffer
,它进一步提高了性能,但只有get
和put
方法,所以如果你需要它是没用的简单直接的集合操作。
结论
我选择选项 2,因为在我的例子中,我正在执行非常密集的操作,但在通常情况下,选项 1 可能是最好的,因为它在复杂性和性能方面取得了平衡。
如果您需要 highest-performance 结构和 read/put 方法就足够了,我会说选项 3 就是您要找的。
希望这对某人有所帮助
我正在 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 而不是数组吗?)或者 如何 我正在构建整个东西(即我需要做一些优化工作)。
如果需要,我会尽快放上代码。
感谢您的帮助。
Self-answer 总结解决方案(感谢@Tenfour04 和@gidds 的回答)
正如@Tenfour04 所述,对于 KMatrix
:
Array<Array<Double>>
的方法
- 一个
Array<DoubleArray>
与原始逻辑保持相同的逻辑,但节省了大量内存并提高了性能; - a 1-Dimensional
DoubleArray
节省了一些额外的内存和性能,但增加了数组的 index-mapping 的复杂性(矩阵的 [i;j] 元素由数组的 [i * w + j] 元素给出),正如@gidds 指出的那样,这可能不值得; - 用
ByteBuffer.allocateDirect(8 * size).asDoubleBuffer()
创建的一维DoubleBuffer
,它进一步提高了性能,但只有get
和put
方法,所以如果你需要它是没用的简单直接的集合操作。
结论 我选择选项 2,因为在我的例子中,我正在执行非常密集的操作,但在通常情况下,选项 1 可能是最好的,因为它在复杂性和性能方面取得了平衡。 如果您需要 highest-performance 结构和 read/put 方法就足够了,我会说选项 3 就是您要找的。
希望这对某人有所帮助