【C#】 最急降下法による多変数関数の最適化
最急降下法を利用して多変数関数の最適化を行うクラスを実装します。最急降下法ではここ(【C#】 勾配ベクトルを計算するクラス - 旅行好きなソフトエンジニアの備忘録)で作成したGradientというクラスを利用します。
public class SteepestDescentMethodMV { private readonly Func<double[], double> _f; private readonly double[] _xn; private readonly double _learningRate; /// <summary> /// コンストラクタ /// </summary> /// <param name="f">多変数関数</param> /// <param name="initialX">初期値</param> /// <param name="learningRate">学習係数</param> public SteepestDescentMethodMV(Func<double[], double> f, double[] initialX, double learningRate) { ValidateArguments(initialX, learningRate); _f = f; _xn = new double[initialX.Length]; Array.Copy(initialX, _xn, _xn.Length); _learningRate = learningRate; } private static void ValidateArguments(double[] initialX, double learningRate) { if (initialX == null) { throw new ArgumentNullException("initialX"); } if (initialX.Length <= 1) { throw new ArgumentOutOfRangeException("initialX", "initialX length must be more than 1"); } if (learningRate <= 0.0) { throw new ArgumentOutOfRangeException("learningRate", "learningRate must be positive"); } } /// <summary> /// 現在の解を取得するためのプロパティ /// </summary> public double[] Xn { get { return _xn; } } /// <summary> /// 最急降下法を利用して多変数関数の最小値を探索するメソッド /// </summary> /// <param name="f">多変数関数</param> /// <param name="initialX">初期値</param> /// <param name="iteration">計算回数</param> /// <param name="learningRate">学習係数</param> /// <returns>関数の最小値を与える変数</returns> public static double[] Compute(Func<double[], double> f, double[] initialX, int iteration, double learningRate) { ValidateArguments(initialX, iteration, learningRate); var xn = new double[initialX.Length]; Array.Copy(initialX, xn, xn.Length); for (int i = 0; i < iteration; ++i) { double[] gradient = Gradient.Compute(f, xn); for (int j = 0; j < xn.Length; ++j) { xn[j] -= learningRate*gradient[j]; } } return xn; } private static void ValidateArguments(double[] initialX, int iteration, double learningRate) { ValidateArguments(initialX, learningRate); if (iteration <= 0) { throw new ArgumentOutOfRangeException("iteration", "iteration must be positive"); } } /// <summary> /// 現在の解を更新するメソッド /// </summary> public void Update() { double[] gradient = Gradient.Compute(_f, _xn); for (int i = 0; i < _xn.Length; ++i) { _xn[i] -= _learningRate*gradient[i]; } } }
次にSteepestDescentMethodMVクラスを利用しての最小値を与えるを求めます。
Func<double[], double> f = x => x[0]*x[0] +x[1]*x[1] + 1.0; var initialX = new double[] { 5.0, 1.0 }; int iteration = 100; double learningRate = 0.1; double[] answer = SteepestDescentMethodMV.Compute(f, initialX, iteration, learningRate);
answer[0]が、answer[1]がに対応しており、両方に0に近い値が入っているため正しく動作していることが分かります。更新時のの遷移を様子を確認したい場合はstaticメソッドではなくSteepestDescentMethodMVクラスをインスタンス化して下記のように利用します。
Func<double[], double> f = x => x[0]*x[0] + x[1]*x[1] + 1.0; var initialX = new double[] { 5.0, 1.0 }; double learningRate = 0.1; var optimizer = new SteepestDescentMethodMV(f, initialX, learningRate); int iteration = 100; var xHistory = new List<double[]>(); for (int i = 0; i < iteration; ++i) { optimizer.Update(); xHistory.Add(optimizer.Xn); }
上記コードでxHistoryの中身を調べることでxの遷移の様子が分かります。
- 作者: 古川正志,渡辺美知子,木下正博,鈴木育男,山本雅人,川上敬
- 出版社/メーカー: コロナ社
- 発売日: 2011/12/06
- メディア: 単行本
- この商品を含むブログ (1件) を見る