HeatonResearchNeuralライブラリ(ニューラルネットワーク)の30倍の高速化

みなさんこんにちは! 多様なニューラルネットワークのライブラリであるHeatonResearchNeural完成の小さな歴史を共有したいと思います。 すぐに私がアナリストとして働くことを予約し、約10年前に正直なプログラマーでなくなった。



しかし、私は自分のプロジェクトをC#で作成しており、自由な時間に開発しています。 自転車を書かないようにするために、私は一度HeatonResearchNeuralをダウンロードしてテープで固定し、テストを静かに進め、コードのロジックを完成させました。 最大の加速のために、計算のソリューション並列化のアーキテクチャを構築し、80-90%のCPU負荷、快適な敵対的な熱が体に注がれていることを確認しました。



一方、私は大容量で、機能するまで長い時間待たなければなりませんでした。 プロファイラーの助けを借りて、突然このバイクのボンネットの下を見ると思われるまで、2台目のサーバーを購入することさえ考えました。 さらに、それはそれ自体ではなく尊敬される居住地のこの記事の印象の下で生まれました。



最初は、自分のコードに確信がありました。 このニューラルネットワークは飛ぶべきものであることは明らかです。そうでなければ、深刻なトピックが作成されません。 しかし、医療参考書を読んだ後、あなたの中で最も怪しい病気の兆候のほとんどを見つけたように、それでもプロファイラーでコードをチェックすることにしました。



プロファイリングが図書館の機能を指すと、冷血な興奮が魂に舞い上がりました。 このような優れたライブラリの開発者が速度について考えたことは明らかですよね? それとも世界はまだ秘密のベッドではなく、明らかに混乱によって支配されていますか? この質問に答えるために、私のプログラムを100サイクル実行した結果を詳しく見てみましょう。これは、ほぼ完全にニューラルネットワークで構成されています。



画像






コールツリーレポートに分類し、最も難しい機能を見つけます。



画像






私たちは彼らに行き、本当に悲痛な光景を見ます。 自分の精神が完全にわからない場合は、背を向けて、GetCol関数が行列からのベクトルの詳細な抽出をどのように処理するかを見ないのが理にかなっています。



public Matrix GetCol(int col) { if (col > this.Cols) { throw new MatrixError("Can't get column #" + col + " because it does not exist."); } double[,] newMatrix = new double[this.Rows, 1]; for (int row = 0; row < this.Rows; row++) { newMatrix[row, 0] = this.matrix[row, col]; } return new Matrix(newMatrix); }
      
      





DotProductへの転送のみ:



  for (i = 0; i < this.next.NeuronCount; i++) { Matrix.Matrix col = this.matrix.GetCol(i); double sum = MatrixMath.DotProduct(col, inputMatrix); this.next.SetFire(i, this.activationFunction.ActivationFunction(sum)); }
      
      





この寄生虫から栄養価の高いギガヘルツいっぱいのビタミンを奪い、2回正確にスラッシュを打つことで、目的の列番号とともにマトリックス全体を一度にDotProductに転送します。



 //Matrix.Matrix col = this.matrix.GetCol(i); double sum = MatrixMath.DotProduct(this.matrix, i, inputMatrix);
      
      





そして、エレガントなレースの代わりにすでに内側に:



  public static double DotProduct(Matrix a, Matrix b) { if (!a.IsVector() || !b.IsVector()) { throw new MatrixError( "To take the dot product, both matrixes must be vectors."); } Double[] aArray = a.ToPackedArray(); Double[] bArray = b.ToPackedArray(); if (aArray.Length != bArray.Length) { throw new MatrixError( "To take the dot product, both matrixes must be of the same length."); } double result = 0; int length = aArray.Length; for (int i = 0; i < length; i++) { result += aArray[i] * bArray[i]; } return result;
      
      





単純なbyとして、bydlokodを彫刻します。



  public static double DotProduct(Matrix a, int i, Matrix b) { double result = 0; if (!b.IsVector()) { throw new MatrixError( "To take the dot product, both matrixes must be vectors."); } if (a.Rows != b.Cols || b.Rows != 1) { throw new MatrixError( "To take the dot product, both matrixes must be of the same length."); } int rows = a.Rows; //    ,    a.Rows     for (int r = 0; r < rows; r++) { result += a[r, i] * b[0, r]; } return result;
      
      





また、配列の外に行くようにバリデーターにコメントすることは意味があります。すべて同じですが、コンパイル時にサイズが静的に設定され、カットするのは難しいです。



  public double this[int row, int col] { get { //Validate(row, col); return this.matrix[row, col]; } set { //Validate(row, col); if (double.IsInfinity(value) || double.IsNaN(value)) { throw new MatrixError("Trying to assign invalud number to matrix: " + value); } this.matrix[row, col] = value; } }
      
      





それで、エキサイティングな瞬間、プログラムの100サイクルを再び開始します。 これらの単純な行動の効果を見たとき、私はほとんどうれしそうになりました。 こんな奇妙な感じで、まるで彼らがこのように30台のサーバーを手に入れてくれたかのように(それは結局クローゼットの中に立っていたが、そこを覗くだけの考えがなかった):



画像






グラフの最初の6秒はデータ準備であるため、実際の作業時間は780秒から26秒に短縮され、もちろんまったく同じ結果になりました。 したがって、加速は30倍でした!



したがって、実践は、マーフィーの法則がアフリカ系アメリカ人が福祉に座っているのと同じくらい安定していることを示しており、何かがうまくいかない場合、それが起こることは間違いありません。 おそらくいくつかのタイプのネットワークがこのコードで動作しないことにも注意する価値があります。必要に応じてテストし、考慮する価値があります。 ご清聴ありがとうございました。これが、制御不能に拡大する宇宙とコードのエントロピーに対する成功した戦いにおいて、少なくとも何らかの形で誰かの助けになることを願っています。



All Articles