我试图在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"));
}
此致
答案 0 :(得分:2)
使用BLAS对Numpy进行极端优化。使用自己的代码可能无法获得如此出色的性能。
点积虽然可以很好地并行化。您可以考虑使用多线程,但说实话,它不值得付出努力。只需找一个为您实现点积的库并使用它!
答案 1 :(得分:2)
您的代码正在进行矩阵乘法。存在用于进行矩阵乘法的快速算法,并且你正在做的是非常慢的O(n ^ 3)[技术上基于列/行长度的O(n * m ^ 2)]。另外,每次分配内存都不是一个好主意。
您的资源:
顺便提一下,如果您想要针对此类事情的桌面性能的最新技术,您可能需要查看CUDA:https://en.wikipedia.org/wiki/CUDA
答案 2 :(得分:1)
让您的C#代码与python代码一样:知道您的语言何时无法与大型犬保持同步,并且当发生这种情况时,请调用常驻BLAS子系统中的本机代码以实现高性能并行原生优化矩阵数学运算。
常驻BLAS子系统由标准API包装。您的C#代码将调用API,但不会知道 - 不知道是件好事! - 当前在主机上安装了哪个特定的BLAS子系统。
我喜欢OpenBLAS。其他人喜欢英特尔MKL(?)。还有一些人喜欢ATLAS。我讨厌ATLAS。
答案 3 :(得分:1)
如果您需要实用的解决方案 - 请使用现有的库。
如果您是出于娱乐/教育目的而这样做:
消除来自最内层循环(GetLength
)的所有函数调用 - 任何函数调用都不能被缓存并导致显着减速。外环可以从相同的优化中受益,但不会带来显着的好处。
首先尝试转置第二个矩阵,以便内部循环访问两个数组的顺序元素。
尝试使用数组而不是2d数组。
Parallel.Foreach
还可以使用Stopwatch
来衡量时间 - Exact time measurement for performance testing