機械学習 - 勾配降下アルゴリズム

4.3.3 勾配計算

    勾配降下法は機械学習で広く使用されています. 線形回帰であろうとロジスティック回帰であろうと, 勾配とは, その点での特定の関数の方向微分がこの方向に沿って最大値を取ることを意味します.の主な目的は、目的関数の最小値を繰り返し見つけるか、最小値に収束することです。

この記事では、下り坂のシーンから始めて、最初に勾配降下アルゴリズムの基本的な考え方を提案し、次に勾配降下アルゴリズムの原理を数学的に説明し、勾配が使用される理由を説明し、最後に勾配降下アルゴリズムの簡単な例を実装します。 .

    勾配降下法の基本的な考え方は、下り坂のプロセスに例えることができます。このようなシナリオを想定してください: 人が山に閉じ込められ、山から降りる必要があります (谷である山の最低点を見つけます)。しかし、この時期は山に濃霧が立ちこめ、視界が悪いため、下山の道が定まらず、周囲の情報を頼りに一歩一歩下山する必要があります。現時点では、勾配降下アルゴリズムを使用して山を下ることができます。やり方は、まず自分の現在位置を基準にして、その位置で一番急なところを見つけてから、下降方向に一歩踏み出し、さらに現在位置を基準にして一番急なところを見つけて歩きます。もう一度 最下点に到達するまで、山を登る場合も同様ですが、このとき勾配上昇アルゴリズムになります。

勾配降下の基本的なプロセスは、下り坂のシーンと非常によく似ています。

まず、微分可能な関数があります。この関数は山を表します。私たちの目標は、この関数の最小値、つまり山の底を見つけることです。前のシナリオの仮定によると、山を下る最速の方法は、現在位置の最も急な方向を見つけてから、この方向を下ることです。これは、特定の点の勾配を見つける関数に対応します。勾配とは逆の方向に移動すると、関数値を最速で下げることができます。勾配の方向は関数の最も速い変化方向であるため (後で詳しく説明します)、この方法を繰り返し使用して勾配を繰り返し取得し、最終的に局所最小値に到達します。これは、下り坂のプロセスに似ています。勾配を見つけると、シーン内の方向を測定する手段である最も急な方向が決定されます。では、なぜ勾配の方向が最も急な方向なのですか? 次に、微分から始めましょう。

 

最初に、問題が与えられます。上に示した関数 f(x) が与えられたとき、f(x) の最小値を見つけます。私たちの大学の数学の知識によると、まず関数を導出し、次によどみ点を計算し、最後によどみ点での関数値を比較して最小値を取得できることがわかっています。しかし明らかに、これは私たちがそれを解決したい方法ではありません. 私たちが学びたいのは機械学習であり、私たちの目的はコンピューターに結果を取得させることです.

  そして、私たちの大学の数学の研究では、上記の解析的方法に加えて、数値解法、つまりダウンヒル法もあります。

ステップ 1: 初期値 x=x 0を割り当てる

ステップ 2: 増分 ∆x をランダムに生成する (増分方向もランダム)

ステップ 3: f(x+Δx)<f(x) の場合、x = x + Δx

ステップ 4: 収束するまでステップ 2 と 3 を繰り返す

多変量関数 f(x,y) (ここでは例としてバイナリ) の場合、同様のダウンヒル アルゴリズムがあります。

ステップ 1: 初期値 x=x 0 、y=y 0を割り当てる

ステップ 2: 増分 ∆x、∆y をランダムに生成する (増分方向もランダム)

ステップ 3: f(x+Δx,y+Δy)<f(x,y) の場合、x=x+Δx,y=y+Δy

ステップ 4: 収束するまでステップ 2 と 3 を繰り返す

山登り法から最小値を見つけると、いくつかの問題があることがわかります。

  1. 初期値 x 0の設定は収束速度に大きく影響する
  2. 増分Δの方向はランダムに生成されるため、効率が低下します。ステップサイズが小さすぎると計算効率が悪く、大きすぎると極値を通りやすくなります
  3. 局所最適が見やすい(関数内に谷が複数ある場合)
  4. 「台地」「尾根」の場合はお取り扱いできません。

                       「プラトー」の状況

登山方法の改善点:

関数の特性に従って、各反復の増分方向と検索ステップ サイズを決定します。

k 回目の反復の後、独立変数は値 x=xk を取り、f(x) はテイラーの式を使用して xk で展開されることに注意してください。

f(x)=f(xk)+f'(xk)(x-xk)+R(x)

(k+1) 回目の繰り返しの後、f(xk+1)<f(xk) (最小値を求めているため) を期待するので、

f(xk+1)-f(xk)=f'(xk)(xk+1-xk)<0

f'(xk)>0 の場合、xk+1-xk<0 が必要であり、f'(xk)>0 の場合、xk+1-xk<0 が必要です。

この必要性に従って、要件を満たす xk+1 を構築できます。

xk+1-xk = -f'(xk)

元 f(xk+1)-f(xk)=f'(xk)(xk+1-xk)

したがって、反復方向が常に正しい方向、つまり山を下る方向であることは、次の不等式によって検証できます。

f(xk+1)-f(xk)=-[f'(xk)]2 <0 関数の値は毎回減少します

さらに、|f'(xk)| の値が非常に大きい場合、xk+1 が xk から大きく外れてしまい、テイラーの式が成り立たなくなります。そのため、通常、小さな係数 γ>0 を導入して、オフセットの程度

xk+1-xk = -γf'(xk)

したがって、反復式が得られます

xk+1= xk -γf'(xk)

多変量関数の場合、多変量関数のテイラー式を使用して、同様の分析プロセスがあり、反復式は次のとおりです。

xk+1= xk -γg(xk)

ここで、x=(x1...xn)T は n 次元ベクトルです。

多変量関数 f(x) の勾配 (ベクトル) となり、γ>0 はステップ サイズまたは学習率と呼ばれるため、この最適化手法は勾配降下法と呼ばれます。

山登り法と比較した勾配降下法:

  1. 反復の各ラウンドで独立変数の方向を更新する問題を解決し、計算効率が高くなります
  2. ステップ サイズは、1 次元の列検索、つまり単項関数 f(xk -γg(xk))-f(xk) (γ>0 が唯一の独立変数) の最小値を見つけることによって決定できます。実際のアプリケーションでは、通常、経験に基づいて、より小さな一定のステップ サイズを設定します。
  3. 勾配降下法自体は、初期値設定によってもたらされる大域最適問題と局所最適問題を解決することはできません。
  4. 関数の最大値を求める場合、導出プロセスは似ていますが、反復式の符号が変更され、勾配昇順法 xk+1= xk +γg(xk) と呼ばれます。

4.3.4 最小値を求める勾配降下法

    Pythonを使用して単純な勾配降下アルゴリズムを実装し、損失関数の最小値を見つけて回帰直線を作成しますこのシナリオは、単純な線形回帰の例です。次の図に示すように、一連の点(データ セット)があるとします。

勾配降下法を使用して、この直線を当てはめますまず、コスト関数を定義する必要があります。ここでは、平均二乗誤差コスト関数(二乗誤差コスト関数とも呼ばれます)を選択します。

次のように数式に注釈を付けます。

  (1) m はデータセット内のデータポイントの数、つまりサンプル数です。

(2) ½ は定数なので、勾配を計算するときに 2 の 2 次乗を乗算すると、ここで ½ がオフセットされます. 当然、冗長な定数係数はなくなり、その後の計算に便利であり、影響はありません。結果。

(3) y は、データ セット内の各点の実際の y 座標の値、つまりクラス ラベルです。

(4) h は予測関数 (仮説関数) であり、各入力 x に従って、予測された y 値が計算に従って取得されます。つまり、 

コスト関数と勾配、および予測の関数形式が明確になります。コードを書き始めることができます。理解の便宜上、コスト関数は上向きの開口部を持つ凹関数 y = 0.5 * (x-0.25)^2 であると仮定します。すべてのコードは次のとおりです 

numpy を np としてインポート

matplotlib を mpl としてインポート

matplotlib.pyplot を plt としてインポート

mpl.rcParams['font.family'] = 'サンセリフ'

mpl.rcParams['font.sans-serif'] = 'SimHei'

mpl.rcParams['axes.unicode_minus'] = False

# 1 次元の損失関数を構築する

デフォルト f1(x):

    return 0.5 * (x-0.25) ** 2 # 上向きの損失関数を想定

デフォルト h1(x):

    return 0.5 * 2 * (x-0.25) # 元の関数の一次導関数

# 勾配降下法を使って解く

GD_X = [] # 各反復座標の x 値を保存します

GD_Y = [] # 各反復座標の y 値を保存します

x = 4 # は、反復の開始位置である x0 に相当します。

alpha = 0.5 # ステップ サイズまたは学習率

f_change = f1(x) # 初期値は x0 での y の値であり、反復後の y の反復条件を判断するために使用されます. 反復後の変化が小さすぎることはできません.

f_current = f_change # y の変化を再帰的な条件判定として使用

GD_X.append(x) # 座標 x の値をリストに格納

GD_Y.append(f_current) # 座標 y の値をリストに格納

# 反復回数

iter_number = 0 # 繰り返し回数の初期値は 0

while f_change > 1e-10 and iter_number < 100: # 無限反復を避けるための反復継続の条件

    反復回数 += 1

    x = x - alpha * h1(x) # 1 回の反復後の x の値

    tmp = f1(x) # 1 回の反復後の y 値

    # y 値の変化が小さすぎないかどうかを判断する

    f_change = np.abs(f_current - tmp)

    f_current = tmp # 現在の座標の y 値を更新します

    GD_X.append(x) # 座標 x の値をリストに格納

    GD_Y.append(f_current) # 座標 y の値をリストに格納

print('最終結果: (%.5f,%.5f)' % (x, f_current))

print('反復回数: %d' % iter_number)

印刷(GD_X)

# ビルドデータ

X = np.arange(-4, 4.5, 0.05)

Y = np.array(list(map(lambda t: f1(t), X)))

# 描く

plt.figure(facecolor='w')

plt.plot(X, Y, 'r-', 線幅=2)

plt.plot(GD_X, GD_Y, 'bo--', 線幅=2)

plt.title('損失関数 $y=0.5*(x-0.25)^2$; \n学習率: %.3f; 最終解: (%.3f, %.3f); 反復回数: %d'% (アルファ、x、f_current、iter_number))

plt.show()

操作の結果は次のとおりです。

 

コードは「Mathematics of Vernacular Machine Learning」から引用されています

おすすめ

転載: blog.csdn.net/xsh_roy/article/details/121454674