繁体   English   中英

如何使我的C#代码更快地计算点积

[英]How to make my C# code faster to compute dot product

我正在尝试在C#中实现神经网络和深度学习代码。 我的教科书中的示例代码是用Python编写的,所以我试图将它们转换为C#。

我的问题是用numpy计算点积比我从头编写的C#代码快得多。

虽然我的numpy代码需要几秒钟来计算点积1000次,但我的C#代码需要更长的时间。

这是我的问题。 如何让我的C#代码更快?

这是numpy代码:

C:\temp>more dot.py
from datetime import datetime

import numpy as np

W = np.random.randn(784, 100)
x = np.random.randn(100, 784)

print(datetime.now().strftime("%Y/%m/%d %H:%M:%S"))

for i in range(0,1000):
    np.dot(x, W)

print(datetime.now().strftime("%Y/%m/%d %H:%M:%S"))

C:\temp>\Python35\python.exe dot.py
2017/02/08 00:49:14
2017/02/08 00:49:16
C:\temp>

这是C#代码:

public static double[,] dot(double[,] a, double[,] b)
{
    double[,] dot = new double[a0, b1];

    for (int i = 0; i < a.GetLength(0); i++)
    {
        for (int j = 0; j < b.GetLength(1); j++)
        {
            // the next loop looks way slow according to the profiler
            for (int k = 0; k < b.GetLength(0); k++)
                dot[i, j] += a[i, k] * b[k, j];
        }
    }
    return dot;
}

static void Main(string[] args)
{
    // compatible function with np.random.randn()
    double[,] W = random_randn(784, 100);
    double[,] x = random_randn(100, 784);

    Console.WriteLine(DateTime.Now.ToString("F"));
    for (int i = 0; i < 1000; i++)
        dot(W, x);
    Console.WriteLine(DateTime.Now.ToString("F"));
}

问候,

Numpy通过使用BLAS进行极端优化。 使用自己的代码可能无法获得如此出色的性能。

点积虽然可以很好地并行化。 您可以考虑使用多线程,但说实话,这不值得付出努力。 只需找一个为您实现点积的库并使用它!

你的代码正在进行矩阵乘法。 存在用于进行矩阵乘法的快速算法,并且你正在做的是非常慢的O(n ^ 3)[技术上基于列/行长度的O(n * m ^ 2)]。 另外,每次分配内存并不是一个好主意。

资源为您服务:

顺便提一下,如果您想要在这种类型的东西中使用最先进的桌面性能,您可能需要查看CUDA: https//en.wikipedia.org/wiki/CUDA

让你的C#代码就像python代码:知道什么时候你的语言跟不上大狗,当发生这种情况时,请调用常驻BLAS子系统中的本机代码,以获得高性能的并行原生优化矩阵数学运算。

常驻BLAS子系统由标准API包装。 您的C#代码将调用API,但不会知道 - 不知道是件好事! - 当前在主机上安装了哪个特定的BLAS子系统。

我喜欢OpenBLAS。 其他人喜欢英特尔MKL(?)。 还有一些人喜欢ATLAS。 我讨厌ATLAS。


如果您需要实用的解决方案 - 使用现有的库。

如果您这样做是出于娱乐/教育目的:

  • 消除来自最内层循环的所有函数调用( GetLength ) - 任何函数调用都不能被缓存并导致显着减慢。 外环可以从相同的优化中受益,但不会带来显着的好处。

  • 尝试首先转置第二个矩阵,以便内部循环访问两个数组的顺序元素。

  • 尝试使用数组而不是2d数组。

  • 当使用数组arras时,尝试在内部循环中使用Length - 这可能会消除至少一个数组的边界检查
  • 尝试使用Parallel.Foreach并行化最外层循环
  • 如果实际问题需要多个非方形矩阵的乘法 - https://en.wikipedia.org/wiki/Matrix_chain_multiplication

还可以使用Stopwatch来测量时间 - 性能测试的精确时间测量

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM