[[389202]] 勾配降下法は、目的関数の負の勾配に従って関数の最小値を見つける最適化アルゴリズムです。 勾配降下法の制限は、すべての入力変数に対して単一のステップ サイズ (学習率) が使用されることです。 AdaGrad や RMSProp などの勾配降下法の拡張機能は、入力変数ごとに個別のステップ サイズを使用するようにアルゴリズムを更新しますが、ステップ サイズが非常に小さな値に急速に減少する可能性があります。適応型モーション推定アルゴリズム (Adam) は、勾配降下法の拡張であり、AdaGrad や RMSProp などの手法の自然な後継であり、目的関数の各入力変数の学習率を自動的に調整し、指数関数的に減少する勾配の移動平均を使用して変数を更新します。 このチュートリアルでは、Adam 最適化アルゴリズムを使用して勾配降下法をゼロから開発する方法を学びます。このチュートリアルを完了すると、次のことが分かります。 - 勾配降下法は、目的関数の勾配を使用して検索空間を移動する最適化アルゴリズムです。
- 勾配降下法は、Adam と呼ばれる偏導関数の減少平均を使用して、各入力変数に対して自動的に適応するステップ サイズを使用するように更新できます。
- Adam 最適化アルゴリズムを最初から実装し、それを目的関数に適用して結果を評価する方法。
チュートリアルの概要 このチュートリアルは、次の 3 つの部分に分かれています。 - 勾配降下法
- Adam最適化アルゴリズム
- アダム勾配降下法
2次元テスト問題 アダムの勾配降下法の最適化 アダムビジュアライゼーション 勾配降下法 勾配降下法は最適化アルゴリズムです。これは、ターゲット目的関数の 1 次導関数を明示的に利用することから、技術的には 1 次最適化アルゴリズムと呼ばれます。一次導関数、または単に「導関数」は、特定の点(たとえば、点)における目的関数の変化率または傾きです。具体的な入力の場合。目的関数が複数の入力変数を取る場合、それは多変量関数と呼ばれ、入力変数はベクトルとして考えることができます。逆に、多変量目的関数の導関数はベクトルとして表示することもでき、勾配と呼ばれることもあります。 勾配: 多変量目的関数の 1 次導関数。 特定の入力に対して、導関数または勾配は目的関数の最も急な上昇の方向を指します。 勾配降下法とは、目的関数の負の勾配に沿って下り、関数の最小値を見つける最小化最適化アルゴリズムを指します。勾配降下アルゴリズムでは、最適化される目的関数とその目的関数の微分関数が必要です。目的関数 f() は、指定された入力セットのスコアを返し、微分関数 f'() は、指定された入力セットの目的関数の微分を返します。勾配降下アルゴリズムでは、入力空間内でランダムに選択された点など、問題の開始点 (x) が必要です。 目的関数を最小化していると仮定し、導関数を計算して入力空間でステップを踏み、目的関数が下り坂に移動することになります。下り坂への移動は、まずステップ サイズ (アルファまたは学習率と呼ばれる) に傾斜を掛けて、入力空間内の移動量を計算することによって実行されます。この値は現在のポイントから減算され、目的関数の勾配に逆らって、つまり下向きに移動することを確認します。 x(t) = x(t-1) – ステップ*f'(x(t-1)) 特定のポイントにおける目的関数の勾配が急であるほど、勾配の大きさが大きくなり、結果として、検索空間で実行されるステップが大きくなります。ステップ サイズ ハイパーパラメータを使用してステップ サイズをスケーリングします。 ステップ サイズ (アルファ): 各反復で勾配に対してアルゴリズムが検索空間内でどれだけ移動するかを制御するハイパーパラメータ。 ステップ サイズが小さすぎると、検索空間内の移動が小さくなり、検索に時間がかかります。ステップ サイズが大きすぎると、検索が検索空間内を飛び回り、最適解をスキップする可能性があります。 勾配降下法の最適化アルゴリズムについて理解できたので、次は Adam アルゴリズムを見てみましょう。 Adam最適化アルゴリズム 適応型モーション推定アルゴリズム (略して「Adam」) は、勾配降下法最適化アルゴリズムの拡張です。このアルゴリズムは、Diederik Kingma 氏と Jimmy Lei Ba 氏による 2014 年の論文「Adam: A Method for Stochastic Optimization」で説明されています。 Adam は、最適化プロセスを高速化すること (最適値に到達するために必要な関数評価の数を減らすなど)、または最適化アルゴリズムのパフォーマンスを向上させること (より良い最終結果を生成するなど) を目指しています。これは、最適化される各入力パラメータのステップ サイズを計算することによって実現されます。重要なのは、各ステップ サイズは、各変数で発生する勾配 (偏導関数) に基づいて、検索プロセスのスループットを自動的に調整することです。 アルゴリズムの各要素を見ていきましょう。まず、検索の一部として最適化される各パラメータについて、それぞれ m と v (実際にはギリシャ文字の nu) と呼ばれるモーメント ベクトルと指数的に重み付けされた無限大ノルムを維持する必要があります。検索開始時に 0.0 に初期化します。 0 = 0 です 0 = 0 です アルゴリズムは t=1 から始まる時刻 t で反復実行され、各反復では新しいパラメータ値のセット x が計算されます (例)。 x(t-1)からx(t)まで。 1 つのパラメータの更新に焦点を当てると、ベクトル演算を介してすべてのパラメータを更新するというアルゴリズムを理解するのは簡単かもしれません。まず、現在のタイムステップでの勾配(偏微分)を計算します。 g(t) = f'(x(t-1)) 次に、勾配とハイパーパラメータ beta1 を使用して第 1 モーメントが更新されます。 m(t) = beta1 * m(t-1) + (1 – beta1) * g(t) 次に、2 乗勾配とハイパーパラメータ beta2 を使用して 2 番目のモーメントが更新されます。 v(t) = beta2 * v(t-1) + (1 – beta2) * g(t)^2 1 次モーメントと 2 次モーメントはゼロ値で初期化されるため、バイアスがかかっています。次に、最初のモーメントを開始点として、最初のモーメントと 2 番目のモーメントの偏差が修正されます。 mhat(t) = m(t)/(1 – beta1(t)) そして2番目の瞬間: vhat(t) = v(t)/(1 – beta2(t)) beta1(t) と beta2(t) は、アルゴリズムの反復中にスケジュールに従って減少する beta1 ハイパーパラメータと beta2 ハイパーパラメータを指すことに注意してください。静的減衰スケジュールを使用することもできますが、この論文では次のことを推奨しています。 ベータ1(t) = ベータ1^t ベータ2(t) = ベータ2^t 最後に、この反復のパラメータの値を計算できます。 x(t) = x(t-1) – アルファ * mhat(t) / (sqrt(vhat(t)) + eps) ここで、alpha はステップ サイズのハイパーパラメータ、eps はゼロ除算エラーが発生しないようにする 1e-8 などの小さな値 (イプシロン)、sqrt() は平方根関数です。 この記事に記載されている更新ルールをより効率的に並べ替えることができることに注意してください。 アルファ(t) = アルファ * sqrt(1 – ベータ2(t)) / (1 – ベータ1(t)) x(t) = x(t-1) – アルファ(t) * m(t) / (sqrt(v(t)) + eps) 要約すると、アルゴリズムには次の 3 つのハイパーパラメータがあります。 - alpha: 初期ステップ サイズ (学習率)。一般的な値は 0.001 です。
- beta1: 最初の運動量の減衰係数。標準値は 0.9 です。
- beta2: 無限大ノルムの減衰係数。標準値は 0.999 です。
次に、このアルゴリズムを Python でゼロから実装する方法を見てみましょう。 アダム勾配降下法 このセクションでは、Adam を使用して勾配降下法最適化アルゴリズムを実装する方法について説明します。 2次元テスト問題 まず、最適化関数を定義しましょう。各次元の入力を二乗し、有効な入力の範囲 (-1.0 から 1.0) を定義する単純な 2 次元関数を使用します。 次の Objective() 関数はこの機能を実装します。 - # 目的関数
- 定義目標(x, y):
- x**2.0 + y**2.0を返す
応答面の曲率を理解するために、データ セットの 3 次元プロットを作成できます。目的関数をプロットする完全な例を以下に示します。 - # テスト関数の 3D プロット
- numpyからarangeをインポート
- numpyからmeshgridをインポート
- matplotlibからpyplotをインポートする
- # 目的関数
- 定義目標(x, y):
- x**2.0 + y**2.0を返す
- # 入力範囲を定義する
- r_min、 r_max = -1.0、1.0
- # 入力範囲を 0.1 刻みで均一にサンプリングする
- x軸=範囲(r_min, r_max, 0.1)
- y軸=範囲(r_min, r_max, 0.1)
- # 軸からメッシュを作成する
- x, y =メッシュグリッド(x軸、y軸)
- # 計算ターゲット
- 結果=目的(x, y)
- # ジェットカラースキームで表面プロットを作成する
- 図= pyplot.figure ()
- 軸=図.gca(投影= '3d' )
- axis.plot_surface(x, y, 結果, cmap = 'jet' )
- # プロットを表示
- pyplot.show()
例を実行すると、目的関数の 3D サーフェス プロットが作成されます。 f(0, 0) = 0 でグローバル最小値を持つ、おなじみのボウル形状を見ることができます。 関数の 2 次元プロットを作成することもできます。これは、後で検索の進行状況をプロットするときに役立ちます。次の例では、目的関数の等高線図を作成します。 - # テスト関数の等高線図
- NumPyからasarrayをインポート
- numpyからarangeをインポート
- numpyからmeshgridをインポート
- matplotlibからpyplotをインポートする
- # 目的関数
- 定義目標(x, y):
- x**2.0 + y**2.0を返す
- # 入力範囲を定義する
- 境界=配列([[-1.0, 1.0], [-1.0, 1.0]])
- # 入力範囲を 0.1 刻みで均一にサンプリングする
- x軸= arange (境界[0,0]、境界[0,1]、0.1)
- y軸= arange (境界[1,0]、境界[1,1]、0.1)
- # 軸からメッシュを作成する
- x, y =メッシュグリッド(x軸、y軸)
- # 計算ターゲット
- 結果=目的(x, y)
- # 50 レベルとジェット カラー スキームで塗りつぶされた等高線図を作成します
- pyplot.contourf(x, y, 結果、レベル= 50 、 cmap = 'jet' )
- # プロットを表示
- pyplot.show()
例を実行すると、目的関数の 2D 等高線プロットが作成されます。ボウルの形状が、色のグラデーションで示されたアウトラインに圧縮されていることがわかります。このグラフを使用して、検索中に探索された特定のポイントをプロットします。 テスト目的関数ができたので、Adam 最適化アルゴリズムを実装する方法を見てみましょう。 Adam 勾配降下法の最適化 Adam を使用した勾配降下法をテスト問題に適用できます。まず、この関数の導関数を計算する関数が必要です。 (x)はx^2の倍数です。 f'(x) = x * 2 x^2 の導関数はどの次元でも x*2 です。 derived() 関数はこれを以下のように実装します。 - # 目的関数の導関数
- 定義導関数(x, y):
- 配列([x * 2.0, y * 2.0])を返す
次に、勾配降下法の最適化を実装します。まず、問題領域内のランダムなポイントを検索の開始点として選択できます。検索範囲を定義する配列があり、各次元に 1 行ずつあり、最初の列でその次元の最小値を定義し、2 番目の列でその次元の最大値を定義しているとします。 - # 初期点を生成する
- x =境界[:, 0] + rand(len(境界)) * (境界[:, 1] - 境界[:, 0])
- スコア=目標値(x[0], x[1])
次に、第 1 モーメントと第 2 モーメントをゼロに初期化する必要があります。 - # 第一モーメントと第二モーメントを初期化する
- m = [0.0 _ の範囲内(bounds.shape[0])]
- v = [0.0 _ の範囲内(bounds.shape[0])]
次に、「n_iter」ハイパーパラメータによって定義されたアルゴリズムの反復を固定回数実行します。 - ...
- # 勾配降下法の反復を実行する
- t が範囲(n_iter)内にある場合:
- ...
最初のステップは、derivative() 関数を使用して現在のソリューションの勾配を計算することです。 - # 勾配を計算する
- 勾配=導関数(解[0], 解[1])
最初のステップは、現在のパラメータ セットに関する導関数を計算することです。 - # 勾配 g(t) を計算する
- g =導関数(x[0], x[1])
次に、Adam 更新計算を実行する必要があります。読みやすさを考慮して、命令型プログラミング スタイルを使用して、これらの計算を一度に 1 つの変数ごとに実行します。 実際には、効率を高めるために NumPy ベクトル演算を使用することをお勧めします。 - ...
- # 一度に 1 つの変数でソリューションを構築します
- iが範囲内(x.shape[0])の場合:
- ...
まず、トルクを計算する必要があります。 - # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)
- m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]
そして二番目の瞬間がやってきました。 - # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2
- v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2
次に、第 1 モーメントと第 2 モーメントのオフセットが修正されます。 - # mhat(t) = m(t) / (1 - beta1(t))
- m mhat = m[i] / (1.0 - beta1**(t+1))
- # vhat(t) = v(t) / (1 - beta2(t))
- v vhat = v[i] / (1.0 - beta2**(t+1))
そして最後に、更新された変数値です。 - # x(t) = x(t-1) - アルファ * mhat(t) / (sqrt(vhat(t)) + eps)
- x[i] = x[i] - アルファ * mhat / (sqrt(vhat) + eps)
次に、最適化するパラメータごとにこれを繰り返します。反復の最後に、新しいパラメータ値を評価し、検索のパフォーマンスを報告できます。 - # 候補ポイントを評価する
- スコア=目標値(x[0], x[1])
- # 進捗状況を報告する
- print(' > %d f(%s) = %.5f' % (t, x, スコア))
これらすべてを、目的関数と導関数の名前とアルゴリズムのハイパーパラメータを受け取り、検索とその評価の最後に見つかった最適なソリューションを返す adam() という関数に組み合わせることができます。 完全な機能は以下に記載されています。 - # Adam による勾配降下アルゴリズム
- def adam(目的関数、導関数、境界、n_iter、アルファ、ベータ1、ベータ2、 eps = 1e -8):
- # 初期点を生成する
- x =境界[:, 0] + rand(len(境界)) * (境界[:, 1] - 境界[:, 0])
- スコア=目標値(x[0], x[1])
- # 第一モーメントと第二モーメントを初期化する
- m = [0.0 _ の範囲内(bounds.shape[0])]
- v = [0.0 _ の範囲内(bounds.shape[0])]
- # 勾配降下法の更新を実行する
- t が範囲(n_iter)内にある場合:
- # 勾配 g(t) を計算する
- g =導関数(x[0], x[1])
- # 一度に 1 つの変数でソリューションを構築します
- iが範囲内(x.shape[0])の場合:
- # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)
- m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]
- # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2
- v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2
- # mhat(t) = m(t) / (1 - beta1(t))
- m mhat = m[i] / (1.0 - beta1**(t+1))
- # vhat(t) = v(t) / (1 - beta2(t))
- v vhat = v[i] / (1.0 - beta2**(t+1))
- # x(t) = x(t-1) - アルファ * mhat(t) / (sqrt(vhat(t)) + eps)
- x[i] = x[i] - アルファ * mhat / (sqrt(vhat) + eps)
- # 候補ポイントを評価する
- スコア=目標値(x[0], x[1])
- # 進捗状況を報告する
- print(' > %d f(%s) = %.5f' % (t, x, スコア))
- [x, スコア]を返す
注: 読みやすさを考慮して、ベクトル化された操作ではなく、リストと命令型のコーディング スタイルを意図的に使用しています。パフォーマンスを向上させるために、NumPy 配列を使用してベクトル化された実装に自由に適応してください。 次に、ハイパーパラメータを定義し、adam() 関数を呼び出してテスト目的関数を最適化します。 この場合、初期ステップ サイズを 0.02、beta1 と beta2 の値をそれぞれ 0.8 と 0.999 にして、アルゴリズムを 60 回繰り返します。これらのハイパーパラメータ値は、試行錯誤の末に見つかりました。 - # 疑似乱数ジェネレータのシード
- 種子(1)
- # 入力範囲を定義する
- 境界=配列([[-1.0, 1.0], [-1.0, 1.0]])
- # 合計反復回数を定義する
- 反復回数= 60
- # ステップサイズ
- アルファ= 0.02
- # 平均勾配の係数
- ベータ1 = 0.8
- # 平均二乗勾配の係数
- ベータ2 = 0.999
- # Adamで勾配降下法検索を実行する
- 最高、スコア= adam (目的、導関数、境界、n_iter、アルファ、ベータ1、ベータ2)
- print('完了しました!')
- print('f(%s) = %f' % (ベスト、スコア))
これらすべてをまとめると、Adam を使用した勾配降下法の最適化の完全な例が次のようになります。 - # 2次元テスト関数に対するアダムによる勾配降下法の最適化
- 数学からインポートsqrt
- NumPyからasarrayをインポート
- numpy.randomからrandをインポート
- numpy.randomからシードをインポート
- # 目的関数
- 定義目標(x, y):
- x**2.0 + y**2.0を返す
- # 目的関数の導関数
- 定義導関数(x, y):
- 配列([x * 2.0, y * 2.0])を返す
- # Adam による勾配降下アルゴリズム
- def adam(目的関数、導関数、境界、n_iter、アルファ、ベータ1、ベータ2、 eps = 1e -8):
- # 初期点を生成する
- x =境界[:, 0] + rand(len(境界)) * (境界[:, 1] - 境界[:, 0])
- スコア=目標値(x[0], x[1])
- # 第一モーメントと第二モーメントを初期化する
- m = [0.0 _ の範囲内(bounds.shape[0])]
- v = [0.0 _ の範囲内(bounds.shape[0])]
- # 勾配降下法の更新を実行する
- t が範囲(n_iter)内にある場合:
- # 勾配 g(t) を計算する
- g =導関数(x[0], x[1])
- # 一度に 1 つの変数でソリューションを構築します
- iが範囲内(x.shape[0])の場合:
- # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)
- m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]
- # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2
- v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2
- # mhat(t) = m(t) / (1 - beta1(t))
- m mhat = m[i] / (1.0 - beta1**(t+1))
- # vhat(t) = v(t) / (1 - beta2(t))
- v vhat = v[i] / (1.0 - beta2**(t+1))
- # x(t) = x(t-1) - アルファ * mhat(t) / (sqrt(vhat(t)) + eps)
- x[i] = x[i] - アルファ * mhat / (sqrt(vhat) + eps)
- # 候補ポイントを評価する
- スコア=目標値(x[0], x[1])
- # 進捗状況を報告する
- print(' > %d f(%s) = %.5f' % (t, x, スコア))
- [x, スコア]を返す
- # 疑似乱数ジェネレータのシード
- 種子(1)
- # 入力範囲を定義する
- 境界=配列([[-1.0, 1.0], [-1.0, 1.0]])
- # 合計反復回数を定義する
- 反復回数= 60
- # ステップサイズ
- アルファ= 0.02
- # 平均勾配の係数
- ベータ1 = 0.8
- # 平均二乗勾配の係数
- ベータ2 = 0.999
- # Adamで勾配降下法検索を実行する
- 最高、スコア= adam (目的、導関数、境界、n_iter、アルファ、ベータ1、ベータ2)
- print('完了しました!')
- print('f(%s) = %f' % (ベスト、スコア))
この例を実行すると、Adam 最適化アルゴリズムがテスト問題に適用され、アルゴリズムの各反復での検索パフォーマンスが報告されます。 注意: アルゴリズムや評価手順の確率的特性、または数値精度の違いにより、結果が異なる場合があります。例を複数回実行し、平均結果を比較することを検討してください。 この場合、入力値が 0.0 に近く、0.0 が 0.0 と評価され、53 回の反復検索後にほぼ最適なソリューションが見つかったことがわかります。 - > 50 f([-0.00056912 -0.00321961]) = 0.00001
- > 51 f([-0.00052452 -0.00286514]) = 0.00001
- > 52 f([-0.00043908 -0.00251304]) = 0.00001
- > 53 f([-0.0003283 -0.00217044]) = 0.00000
- > 54 f([-0.00020731 -0.00184302]) = 0.00000
- > 55 f([-8.95352320e-05 -1.53514076e-03]) = 0.00000
- > 56 f([ 1.43050285e-05 -1.25002847e-03]) = 0.00000
- > 57 f([ 9.67123406e-05 -9.89850279e-04]) = 0.00000
- > 58 f([ 0.00015359 -0.00075587]) = 0.00000
- > 59 f([ 0.00018407 -0.00054858]) = 0.00000
- 終わり!
- ([ 0.00018407 -0.00054858])= 0.000000
アダムビジュアライゼーション Adam 検索の進行状況をドメインの等高線図にプロットできます。これにより、アルゴリズムの反復中に検索の進行状況を直感的に理解できるようになります。検索中に見つかったすべてのソリューションのリストを維持し、検索の終了時にこのリストを返すように、adam() 関数を更新する必要があります。これらの変更を含む機能の更新バージョンを以下に示します。 - # Adam による勾配降下アルゴリズム
- def adam(目的関数、導関数、境界、n_iter、アルファ、ベータ1、ベータ2、 eps = 1e -8):
- ソリューション=リスト()
- # 初期点を生成する
- x =境界[:, 0] + rand(len(境界)) * (境界[:, 1] - 境界[:, 0])
- スコア=目標値(x[0], x[1])
- # 第一モーメントと第二モーメントを初期化する
- m = [0.0 _ の範囲内(bounds.shape[0])]
- v = [0.0 _ の範囲内(bounds.shape[0])]
- # 勾配降下法の更新を実行する
- t が範囲(n_iter)内にある場合:
- # 勾配 g(t) を計算する
- g =導関数(x[0], x[1])
- # 一度に 1 つの変数でソリューションを構築します
- iが範囲内(bounds.shape[0])の場合:
- # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)
- m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]
- # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2
- v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2
- # mhat(t) = m(t) / (1 - beta1(t))
- m mhat = m[i] / (1.0 - beta1**(t+1))
- # vhat(t) = v(t) / (1 - beta2(t))
- v vhat = v[i] / (1.0 - beta2**(t+1))
- # x(t) = x(t-1) - アルファ * mhat(t) / (sqrt(vhat(t)) + ep)
- x[i] = x[i] - アルファ * mhat / (sqrt(vhat) + eps)
- # 候補ポイントを評価する
- スコア=目標値(x[0], x[1])
- # 解決策を追跡する
- ソリューション.append(x.copy())
- # 進捗状況を報告する
- print(' > %d f(%s) = %.5f' % (t, x, スコア))
- リターンソリューション
その後、前と同じように検索を実行しますが、今回は最適な最終ソリューションではなくソリューションのリストを取得します。 - # 疑似乱数ジェネレータのシード
- 種子(1)
- # 入力範囲を定義する
- 境界=配列([[-1.0, 1.0], [-1.0, 1.0]])
- # 合計反復回数を定義する
- 反復回数= 60
- # ステップサイズ
- アルファ= 0.02
- # 平均勾配の係数
- ベータ1 = 0.8
- # 平均二乗勾配の係数
- ベータ2 = 0.999
- # Adamで勾配降下法検索を実行する
- ソリューション= adam (目的関数、導関数、境界、n_iter、アルファ、ベータ1、ベータ2)
その後、前と同じように目的関数の等高線図を作成できます。 - # 入力範囲を 0.1 刻みで均一にサンプリングする
- x軸= arange (境界[0,0]、境界[0,1]、0.1)
- y軸= arange (境界[1,0]、境界[1,1]、0.1)
- # 軸からメッシュを作成する
- x, y =メッシュグリッド(x軸、y軸)
- # 計算ターゲット
- 結果=目的(x, y)
- # 50 レベルとジェット カラー スキームで塗りつぶされた等高線図を作成します
- pyplot.contourf(x, y, 結果、レベル= 50 、 cmap = 'jet' )
最後に、検索中に見つかった各ソリューションを、線で結ばれた白い点としてプロットできます。 - # サンプルを黒い円としてプロットする
- ソリューション= asarray (ソリューション)
- pyplot.plot(ソリューション[:, 0], ソリューション[:, 1], '.-',色= 'w' )
これらすべてを念頭に置いて、テスト問題に対して Adam 最適化を実行し、その結果をシルエット プロットにプロットする完全な例を次に示します。 - # テスト関数の等高線図にアダム検索をプロットする例
- 数学からインポートsqrt
- NumPyからasarrayをインポート
- numpyからarangeをインポート
- numpy.randomからrandをインポート
- numpy.randomからシードをインポート
- numpyからmeshgridをインポート
- matplotlibからpyplotをインポートする
- mpl_toolkits.mplot3d から Axes3D をインポートします
- # 目的関数
- 定義目標(x, y):
- x**2.0 + y**2.0を返す
- # 目的関数の導関数
- 定義導関数(x, y):
- 配列([x * 2.0, y * 2.0])を返す
- # Adam による勾配降下アルゴリズム
- def adam(目的関数、導関数、境界、n_iter、アルファ、ベータ1、ベータ2、 eps = 1e -8):
- ソリューション=リスト()
- # 初期点を生成する
- x =境界[:, 0] + rand(len(境界)) * (境界[:, 1] - 境界[:, 0])
- スコア=目標値(x[0], x[1])
- # 第一モーメントと第二モーメントを初期化する
- m = [0.0 _ の範囲内(bounds.shape[0])]
- v = [0.0 _ の範囲内(bounds.shape[0])]
- # 勾配降下法の更新を実行する
- t が範囲(n_iter)内にある場合:
- # 勾配 g(t) を計算する
- g =導関数(x[0], x[1])
- # 一度に 1 つの変数でソリューションを構築します
- iが範囲内(bounds.shape[0])の場合:
- # m(t) = beta1 * m(t-1) + (1 - beta1) * g(t)
- m[i] = beta1 * m[i] + (1.0 - beta1) * g[i]
- # v(t) = beta2 * v(t-1) + (1 - beta2) * g(t)^2
- v[i] = beta2 * v[i] + (1.0 - beta2) * g[i]**2
- # mhat(t) = m(t) / (1 - beta1(t))
- m mhat = m[i] / (1.0 - beta1**(t+1))
- # vhat(t) = v(t) / (1 - beta2(t))
- v vhat = v[i] / (1.0 - beta2**(t+1))
- # x(t) = x(t-1) - アルファ * mhat(t) / (sqrt(vhat(t)) + ep)
- x[i] = x[i] - アルファ * mhat / (sqrt(vhat) + eps)
- # 候補ポイントを評価する
- スコア=目標値(x[0], x[1])
- # 解決策を追跡する
- ソリューション.append(x.copy())
- # 進捗状況を報告する
- print(' > %d f(%s) = %.5f' % (t, x, スコア))
- リターンソリューション
- # 疑似乱数ジェネレータのシード
- 種子(1)
- # 入力範囲を定義する
- 境界=配列([[-1.0, 1.0], [-1.0, 1.0]])
- # 合計反復回数を定義する
- 反復回数= 60
- # ステップサイズ
- アルファ= 0.02
- # 平均勾配の係数
- ベータ1 = 0.8
- # 平均二乗勾配の係数
- ベータ2 = 0.999
- # Adamで勾配降下法検索を実行する
- ソリューション= adam (目的関数、導関数、境界、n_iter、アルファ、ベータ1、ベータ2)
- # 入力範囲を 0.1 刻みで均一にサンプリングする
- x軸= arange (境界[0,0]、境界[0,1]、0.1)
- y軸= arange (境界[1,0]、境界[1,1]、0.1)
- # 軸からメッシュを作成する
- x, y =メッシュグリッド(x軸、y軸)
- # 計算ターゲット
- 結果=目的(x, y)
- # 50 レベルとジェット カラー スキームで塗りつぶされた等高線図を作成します
- pyplot.contourf(x, y, 結果、レベル= 50 、 cmap = 'jet' )
- # サンプルを黒い円としてプロットする
- ソリューション= asarray (ソリューション)
- pyplot.plot(ソリューション[:, 0], ソリューション[:, 1], '.-',色= 'w' )
- # プロットを表示
- pyplot.show()
例を実行すると、前と同じように検索が実行されますが、この場合は目的関数の等高線プロットが作成されます。 この場合、検索中に見つかった各ソリューションは、最適なポイントから始まり、グラフの中央の最適なポイントに徐々に近づいていき、白い点で表示されていることがわかります。 |