2017-02-07 5 views
3

私はC#でニューラルネットワークと深い学習コードを実装しようとしています。私のテキストブックのサンプルコードはPythonで書かれているので、私はそれらをC#に変換しようとしています。ドットプロダクトを計算するために私の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

は、なぜあなたは最初からニューラルネットワークを実装していますか?学習の練習であれば、コードの実行速度はそれほど重要ではありません。それがうまく機能するようにするには、既に書かれた高品質のソフトウェアを使用してください。 TensorFlow、H2O、Torchのようなニューラルネットワークモデルを持つ多くのパッケージがあります。それらはC#で一人でできるものより多くの機能と高速性を備えています。 –

+0

右。 C#と深い学習の両方を学ぶためだけのものですが、ドットプロダクトを計算するのが予想していた速度より遅いことがわかりました。教科書の例(C#に移植)を実行するのは苦労しました。ですから、私はパフォーマンスを改善したいと思います。そして、私は、パフォーマンスとより良い実装の面で、私の将来の生産システムにいくつかの既存のライブラリを使用するつもりです。 – snaga

答えて

2

numpyのはめちゃめちゃBLASを使用することによって最適化されています。おそらく、自分のコードを使ってこのような良いパフォーマンスを得ることはできません。

ドットプロダクトはとてもうまく並列化できますが、あなたはマルチスレッドで作業することができますが、正直言って努力する価値はありません。ドットプロダクトを実装するライブラリを探して、それを使用してください!

+0

ありがとう! OpenBLASをC#から試してみたい! – snaga

1

あなたのC#コードをPythonコードのようにしてください:あなたの言語が大きな犬に追いつけない時を知って、それが起こると、常駐BLASサブシステムのネイティブコードを呼び出して、数学演算。

常駐BLASサブシステムは標準APIでラップされています。あなたのC#コードはAPIを呼び出しますが、わかりません - 良いことは分かっていません! - 特定のBLASサブシステムが現在ホストにインストールされています。

私はOpenBLASが好きです。 Intel MKL(?)のような他の人。 ATLASのようなものもあります。私はATLASが嫌いです。

+0

>あなたの言語が大きな犬に追いつけない時を知ってください。そうなると、常駐BLASサブシステムのネイティブコードを呼び出すと、高性能パラレルネイティブ最適化マトリックス演算が実行されます。 実際、これは私が学びたかったものです.BLASを学び、それをC#から呼び出す方法だと思います。ありがとう! – snaga

2

あなたのコードは行列の乗算を行っています。行列の乗算を行うための高速アルゴリズムがありますが、行/列の長さに基づいて非常に遅いO(n^3)[技術的にはO(n * m^2)]です。さらに、毎回メモリを割り当てることをお勧めします。あなたのための

資源:

ところであなたは事のこのタイプのデスクトップのパフォーマンスで最先端技術をしたい場合は、CUDAに見たいと思うかもしれません。 https://en.wikipedia.org/wiki/CUDA

+0

ありがとう!私は行列操作とその最適化には新しいので、それを学びます。 CUDAテクノロジーも同様です。 – snaga

1

実用的な解決策が必要な場合は、既存のライブラリを使用します。

あなたは娯楽​​/教育目的のためにこれをやっている場合は、次の

  • は、すべての機能を排除し、最も内側のループ(GetLength)から呼び出されます - 任意の関数呼び出しは、キャッシュされ、大幅なスローダウンにつながることができません。外部ループは同じ最適化の恩恵を受けるかもしれませんが、大きな利点はありません。

  • 2番目の行列を最初に転置して、内部ループが両方の配列の順次要素にアクセスするようにしてください。

  • 2d配列の代わりに配列の配列を使用してください。

  • アレイの使用アラスは、内側ループの長さを使用しようとする - 実際の問題は、複数の乗算を要求する場合は少なくとも1つのアレイ
  • に境界チェックを排除することができるParallel.Foreach
  • と最も外側のループを並列化してみてください非正方行列 - https://en.wikipedia.org/wiki/Matrix_chain_multiplication

も時間を測定するStopwatchを使用 - Exact time measurement for performance testing

+0

素晴らしいヒントありがとう! ええ、私はC#とニューラルネットワーク/ディープラーニングの新機能ですので、C#とニューラルネットワーク/ディープ学習アルゴリズムの両方を習得するのは私のおもちゃプロジェクトです。 C#で数値アルゴリズムを実装するためのヒントを探しています。私はあなたのヒントをできるだけ早く試してみたい。 もう一度おねがいします! – snaga

関連する問題