ニューラル ネットワークを作成してトレーニングする小さなプロジェクトを C# で作成しました。詳細については、こちらの以前の質問を参照してください: ( https://scicomp.stackexchange.com/questions/19481 )。
十分なトレーニングを行った後、ニューラル ネットワークは適切に機能しますが、自分で作成したヒル クライミング アルゴリズムが完全ではない可能性があることに気づき、改善のための提案を探しています。特に、適応度評価関数の呼び出しを少なくして局所最適に到達できるでしょうか?
C# での単純なヒル クライミング アルゴリズムの例は Web にあまりないようです。.NET Math Library がありますが、何かにお金を払う必要はありません。
ヒル クライミング アルゴリズムは、ネットワーク内のすべての重みとすべてのバイアスに対して実行され、ネットワークをトレーニングします。複数のパスを実行します。バックプロパゲーションを調べましたが、これは 1 つのトレーニング例にのみ適用されるようです。トレーニング データには約 7000 の例があり、フィットネス関数はそれらすべてのネットワークの平均パフォーマンスを評価し、連続 (ダブル)スコア。
これが私の現在のコードです:
public static double ImproveProperty(ref double property, double startingFitness, int maxIters, Random r, ref Defs.Network network, Func<Defs.Network, double> fitnessFunction)
{
//Record starting values
var lastFitness = startingFitness;
var lastValue = property;
//Randomise magnitude of change to reduce chance
//of getting stuck in local optimums
var magnitude = r.NextDouble();
var positive = true;
var iterCount = 0f;
var magnitudeChange = 5;
while (iterCount < maxIters)
{
iterCount++;
if (positive)
{ //Try adding a positive value to the property
property += magnitude;
//Evaluate the fitness
var fitness = fitnessFunction(network);
if (fitness == lastFitness)
{ //No change in fitness, increase the magnitude and re-try
magnitude *= magnitudeChange;
property = lastValue;
}
else if (fitness < lastFitness)
{ //This change decreased the fitness (bad)
//Put the property back and try going in the negative direction
property = lastValue;
positive = false;
}
else
{ //This change increased the fitness (good)
//on the next iteration we will try
//to apply the same change again
lastFitness = fitness;
lastValue = property;
//don't increase the iteration count as much
//if a good change was made
iterCount -= 0.9f;
}
}
else
{ //Try adding a negative value to the property
property -= magnitude;
var fitness = fitnessFunction(network);
if (fitness == lastFitness)
{
//No change in fitness, increase the magnitude and re-try
magnitude *= magnitudeChange;
property = lastValue;
}
else if (fitness < lastFitness)
{
//This change decreased the fitness (bad)
//Now we know that going in the positive direction
//and the negative direction decreases the fitness
//so make the magnitude smaller as we are probably close to an optimum
property = lastValue;
magnitude /= magnitudeChange;
positive = true;
}
else
{
//This change increased the fitness (good)
//Continue in same direction
lastFitness = fitness;
lastValue = property;
iterCount -= 0.9f;
}
}
//Check bounds to prevent math functions overflowing
if (property > 100)
{
property = 100;
lastFitness = fitnessFunction(network);
return lastFitness;
}
else if (property < -100)
{
property = -100;
lastFitness = fitnessFunction(network);
return lastFitness;
}
}
return lastFitness;
}
フィットネス関数は非常にコストがかかるため、できるだけ呼び出さないようにする必要があります。フィットネス関数の呼び出しを減らして局所最適に到達するための改善を探しています。局所最適に行き詰まることはあまり問題ではありません。ネットワーク内のさまざまな重みとバイアスの値に対してフィットネス関数をグラフ化しました。通常、グラフには 1 ~ 3 個の局所最適があるように見えます。ネットワークが数回のパスで同じ適合性を維持している場合は、この関数にパラメーターを追加して、ランダムな値からヒル クライミングを再開することを試みることができます。