gpt4 book ai didi

c# - 紧密循环性能 C# 中的二维数组与数组数组

转载 作者:行者123 更新时间:2023-11-30 20:35:38 28 4
gpt4 key购买 nike

我看了一下,没有看到任何能完全回答我的问题的东西。

我并不是最擅长创建准确的“现实生活”测试的人,所以我不确定这是否是问题所在。基本上我想创建一些简单的神经网络来创建一些效果 Gridworld .这些神经网络的性能至关重要,我不希望隐藏层成为瓶颈。

我宁愿使用更多内存并更快,所以我选择使用数组而不是列表(因为列表对数组有额外的边界检查)。数组并不总是满的,但是因为 if 语句(检查元素是否为空)直到最后都是相同的,所以可以预测它并且根本没有性能下降。

我的问题来自于我如何存储数据供网络处理。我认为由于 2D 数组将所有数据存储在一起,所以缓存更明智并且运行速度更快。但是从我的模拟测试来看,数组数组在这种情况下表现得更好。

一些代码:

    private void RunArrayOfArrayTest(float[][] testArray, Data[] data)
{
for (int i = 0; i < testArray.Length; i++) {
for (int j = 0; j < testArray[i].Length; j++) {
var inputTotal = data[i].bias;

for (int k = 0; k < data[i].weights.Length; k++) {
inputTotal += testArray[i][k];
}
}
}
}

private void Run2DArrayTest(float[,] testArray, Data[] data, int maxI, int maxJ)
{
for (int i = 0; i < maxI; i++) {
for (int j = 0; j < maxJ; j++) {
var inputTotal = data[i].bias;

for (int k = 0; k < maxJ; k++) {
inputTotal += testArray[i, k];
}
}
}
}

这是定时的两个函数。每个“生物”都有自己的网络(第一个 for 循环),每个网络都有隐藏节点(第二个 for 循环),我需要找到每个输入的权重总和(第三个循环)。在我的测试中,我剥离了它,这样它就不是我在实际代码中所做的,但会发生相同数量的循环(数据变量将拥有它自己的二维数组,但我不想可能扭曲结果) .由此我试图了解哪个更快,令我惊讶的是数组的数组。

开始测试的代码:

        // Array of Array test
Stopwatch timer = Stopwatch.StartNew();

RunArrayOfArrayTest(arrayOfArrays, dataArrays);

timer.Stop();
Console.WriteLine("Array of Arrays finished in: " + timer.ElapsedTicks);

// 2D Array test
timer = Stopwatch.StartNew();

Run2DArrayTest(array2D, dataArrays, NumberOfNetworks, NumberOfInputNeurons);

timer.Stop();
Console.WriteLine("2D Array finished in: " + timer.ElapsedTicks);

只是想展示我是如何测试它的。在 Release模式下的结果给我这样的值:

Array of Arrays finished in: 8972
2D Array finished in: 16376

有人可以向我解释我做错了什么吗?为什么在这种情况下数组的数组要快这么多?二维数组不是都存储在一起,这意味着它对缓存更友好吗?

请注意,我确实需要这个速度很快,因为它需要对每帧数十万 - 数百万个数字求和,就像我说的那样,我不希望这是一个问题。我知道这在未来可以很容易地实现多线程,因为每个网络都是完全独立的,甚至每个节点都是完全独立的。

我想的最后一个问题是,这样的东西可以在 GPU 上运行吗?我认为 GPU 不会努力拥有大量具有大量输入/隐藏神经元的网络。

最佳答案

在 CLR 中,有两种不同类型的数组:

  • 向量,它们是从零开始的一维数组
  • 数组,可以有非零基数和多维度

您的“数组的数组”是 CLR 术语中的“向量的向量”。

向量基本上比数组快得多。数组可能会在以后的 CLR 版本中得到进一步优化,但我怀疑它是否会像向量一样受到喜爱,因为它们很少被使用。要使 CLR 数组更快,您无能为力。正如您所说,它们对缓存更友好,但它们有 CLR 损失。

但是,您已经可以通过每行仅执行一次第一个索引操作来改进数组的数组代码:

private void RunArrayOfArrayTest(float[][] testArray, Data[] data)
{
for (int i = 0; i < testArray.Length; i++) {

// These don't change in the loop below, so extract them
var row = testArray[i];
var inputTotal = data[i].bias;
var weightLength = data[i].weights.Length;
for (int j = 0; j < row.Length; j++) {
for (int k = 0; k < weightLength; k++) {
inputTotal += row[k];
}
}
}
}

如果你想获得缓存友好性并且仍然使用向量,你可以有一个单个 float[] 并自己执行索引......但我' d 可能从数组的数组方法开始。

关于c# - 紧密循环性能 C# 中的二维数组与数组数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37717724/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com