私は.Netで開発された遺伝的機械学習プロジェクトに取り組んでいます(Matlab – My Normとは対照的に)。私はプロの.netコーダーではないので、初心者の実装を許してください。
プロジェクト自体は巨大なので、詳細については説明しませんが、基本的に人工ニューラル ネットワーク (決定木など) の集団は、この場合は一連の感覚入力を使用する問題ドメインでそれぞれ評価されます。個体群の中で最も成績の良い個体は、子孫を繁殖させて (両親から傾向を受け継いで) 産むことができます。許容できる解決策が見つかるまで、進化は続きます。発見されると、最終的に進化した「ネットワーク」がラボから抽出され、軽量の実世界のアプリケーションに配置されます。この技術は、自動車の自動運転、機械的安定性制御、データセンターの負荷分散など、通常のプログラムではほとんど不可能または時間がかかりすぎる非常に複雑な制御ソリューションの開発に使用できます。
とにかく、プロジェクトはこれまでのところ大成功を収めており、驚くべき結果を生み出していますが、唯一の問題は、より大きなデータセットに移行するとパフォーマンスが非常に低下することです. 私はちょうど私のコードであることを望んでいるので、専門家の助けを本当に感謝しています.
このプロジェクトでは、理想に近い解に収束するまでに約 7 日かかることがよくあります。パラメータを少し調整して結果を待つのは、あまりにも苦痛です。
基本的に、複数の並列スレッドが非常に大きなデータセットの連続したセクションを読み取る必要があります (データはロードされると変更されません)。データセットは、約 300 から 1000 の Double が連続しており、50 万行を超えるもので構成されています。データセットは 2 GB の .Net オブジェクト制限を超える可能性があるため、通常の 2 次元配列に格納することはできません。これを回避する最も簡単な方法は、単一配列の汎用リストを使用することでした。
並列スケーラビリティは大きな制限要因のようです。通常、朝食用に大きなデータセットを消費する 32 個の Xeon コアを備えたサーバーの獣でコードを実行すると、Corei3 デスクトップよりも多くのパフォーマンスが得られないからです!
コアの数が増えると、パフォーマンスの向上は急速に低下します。
コードのプロファイリングから (私の限られた知識で)、複数のスレッドからデータセットを読み取る際に大量の競合が発生しているという印象を受けます。
ジャグ配列とさまざまな同時コレクションを使用してさまざまなデータセットの実装を試してみましたが、役に立ちませんでした。
オリジナルのコア実装に似ているが、同様の読み取りパフォーマンスの問題と並列スケーラビリティの問題を示す、ベンチマーク用の簡単で汚いコードをノックアップしました。
どんな考えや提案も大歓迎です。または、これが私が得ようとしている最高のものであることを確認してください.
どうもありがとう
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
//Benchmark script to time how long it takes to read dataset per iteration
namespace Benchmark_Simple
{
class Program
{
public static TrainingDataSet _DataSet;
public static int Features = 100; //Real test will require 300+
public static int Rows = 200000; //Real test will require 500K+
public static int _PopulationSize = 500; //Real test will require 1000+
public static int _Iterations = 10;
public static List<NeuralNetwork> _NeuralNetworkPopulation = new List<NeuralNetwork>();
static void Main()
{
Stopwatch _Stopwatch = new Stopwatch();
//Create Dataset
Console.WriteLine("Creating Training DataSet");
_DataSet = new TrainingDataSet(Features, Rows);
Console.WriteLine("Finished Creating Training DataSet");
//Create Neural Network Population
for (int i = 0; i <= _PopulationSize - 1; i++)
{
_NeuralNetworkPopulation.Add(new NeuralNetwork());
}
//Main Loop
for (int i = 0; i <= _Iterations - 1; i++)
{
_Stopwatch.Restart();
Parallel.ForEach(_NeuralNetworkPopulation, _Network => { EvaluateNetwork(_Network); });
//######## Removed for simplicity ##########
//Run Evolutionary Genetic Algorithm on population - I.E. Breed the strong, kill of the weak
//##########################################
//Repeat until acceptable solution is found
Console.WriteLine("Iteration time: {0}", _Stopwatch.ElapsedMilliseconds / 1000);
_Stopwatch.Stop();
}
Console.ReadLine();
}
private static void EvaluateNetwork(NeuralNetwork Network)
{
//Evaluate network on 10% of the Training Data at a random starting point
double Score = 0;
Random Rand = new Random();
int Count = (Rows / 100) * 10;
int RandonStart = Rand.Next(0, Rows - Count);
//The data must be read sequentially
for (int i = RandonStart; i <= RandonStart + Count; i++)
{
double[] NetworkInputArray = _DataSet.GetDataRow(i);
//####### Dummy Evaluation - just give it somthing to do for the sake of it
double[] Temp = new double[NetworkInputArray.Length + 1];
for (int j = 0; j <= NetworkInputArray.Length - 1; j++)
{
Temp[j] = Math.Log(NetworkInputArray[j] * Rand.NextDouble());
}
Score += Rand.NextDouble();
//##################
}
Network.Score = Score;
}
public class TrainingDataSet
{
//Simple demo class of fake data for benchmarking
private List<double[]> DataList = new List<double[]>();
public TrainingDataSet(int Features, int Rows)
{
Random Rand = new Random();
for (int i = 1; i <= Rows; i++)
{
double[] NewRow = new double[Features];
for (int j = 0; j <= Features - 1; j++)
{
NewRow[j] = Rand.NextDouble();
}
DataList.Add(NewRow);
}
}
public double[] GetDataRow(int Index)
{
return DataList[Index];
}
}
public class NeuralNetwork
{
//Simple Class to represent a dummy Neural Network -
private double _Score;
public NeuralNetwork()
{
}
public double Score
{
get { return _Score; }
set { _Score = value; }
}
}
}
}