[BOSTCAMP AI技術/DAy 4]AI Math 3強−傾斜降下法(1/2,ソフト)

16052 ワード

傾斜降下法を知るための事前知識学習


びぶん


  • 微分は変数の移動に伴う関数値の変化を測定するツールであり,最適化で最もよく用いられる方法である.

  • f’(x)=lim89 n→0 f(x+h)lim nto 0}{f(x+h)-f(x)over h}f’(x)=limn→0 hf(x+h)87 f(x)※微分の変化率を限界(限界)と定義
    (x)=x 2+2 x+3=微分>f′(x)=lim\n→0 f(x+x+2 x+3=lim\n n n n n→0(x+2++h)=2 xx+2 x+2 x+3\overset{{2 xxx+3\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\’(x)=limn→0 hf(x+h)=f(x)=limn→0(2 x+2+h)=2 x+2

  • 図に示すように、微分は、関数fffの与えられた点(x,f(x))(x,f(x))(x,f(x))上の接線を求める傾斜角である.
  • 微分を計算するには、値が連続していなければならない
  • hhhは0に収束し、x上で接線が傾く


  • pythonに微分
    import sympy as sym #함수를 sumbol, 즉 기호로 인식
                        #sympy.diff 로 미분을 컴퓨터로 계산 가능
    from sympy.abc import x
    sym.diff(sym.poly(x**2 + x*2 + 3), x)
    >> Poly(2*x + 2, x, domain = 'ZZ')

    微分値の利用



  • 微分値が与えられた場合、関数値が増加するか減少するかを知るには、どの方向に移動すればよいかを知ることができます.


  • 関数値を増やした場合=>x+f’(x)x+f’(x)x+f’(x)x+f’(x)
  • 微分値が負の場合、微分値を加えて左に移動し、関数値が増加
  • 逆に微分値が正の値であれば微分値を加えて右に移動し、関数値が増加

  • 関数値を減らした場合=>x∮f’(x)x-f’(x)x∮f’(x)
  • 微分値が負(下図参照)の場合、微分値を加えて右に移動し、関数値が増加
  • 逆に微分値が正の値であれば微分値を加えると左側に移動し関数値が増加する


  • 微分値を増やして目標関数を最大化する傾き上昇法(勾配上昇)

    微分値を加えて目標関数を最小化する傾き降下法(勾配降下)

    ※極値(最大、最小)、すなわち微分値が0の場合更新終了

    チルトダウンアルゴリズム

  • 変数が1つしかない場合
  • 勾配:微分の関数を計算する
  • init:起点
  • lr(学習率):学習率
  • lrで更新速度を調整
  • この条件により、実際のチルトダウンアルゴリズムの最小値への収束に大きな影響を与える
  • eps:アルゴリズム終了条件
  • 実際、計算機計算時の微分が正確にゼロになることは不可能であるため、eps未満では学習終了
  • import numpy as np
    import sympy as sym
    from sympy.abc import x
    
    def func(val):
        func = sym.poly(x**2 + x*2 + 3)
        return fun.subs(x,val), fun
    
    def func_gradient(fun,val):
        _, function = fun(val)
        diff = sym.diff(function, x)
        return diff.subs(x,val) diff
    
    def gradient_descent(fun, init_point, lr_rate = 0.01, epsilon = 0.00001):
        cnt = 0
        val = init_point
        diff, _ = func_gradient(fun, val)
        while np.abs(diff) > epsilon:
            val = val - lr_rate*diff
            diff, _ = func_gradient(fun, val)
            cnt +=1
        print("함수: {fun(val)[1]}, 연산횟수: {cnt}, chlthwja: ({val}, {fun(val)[0]})"
    
    gradient_descent(fun = func, init_point=np.random.uniform(-2,2))

  • 2 D入力の場合
  • ベクトル入力、偏微分使用
    ∂xif′(x)=lim⁡n→0f(x+hei)−f(x)h\partial_{x_{i}} f'(x) =\lim_{n\to0}{f(x+he_{i}) - f(x)\over h}∂xi​​f′(x)=limn→0​hf(x+hei​)−f(x)​
    ※eieiはiの1番目の値が1で、残りは0の単位ベクトルのみ
    ※∂xipartic{x i}xi表示値をXiX iXi変数で微分
  • f(x,y)=x2+2xy+3+cos(x+2y)f(x,y) = x^2 + 2xy + 3 + cos(x + 2y)f(x,y)=x2+2xy+3+cos(x+2y)
    xxxの場合、偏微分=>∂xf(x,y)=2 x+2 y+3局所x}f(x,y)=2 x+2 y+3-sin(x+2 y)∂xf(x,y)=2 x+2 y+3∂sin(x+2 y)

  • 2 D入力の場合
  • 多次元の場合も偏微分を用いる
  • 各変数ごとに偏微分を計算する勾配ベクトルを用いた傾斜降下法(or傾斜上昇法)
    ∇f=(∂x1f,∂x2f,⋯ ,∂xdf)\nabla f = ({\partial_{x_1}f,\partial_{x_2 }f,\cdots,\partial_{x_d}f)}∇f=(∂x1​​f,∂x2​​f,⋯,∂xd​​f)
    ※ ∇\nabla∇ : nabla
  • •前に使用した微分値f"(x)"(x,x,x,x,x,x,x,x,x,x)の代わりにfnabla f∇f∇fを使用する
    ∇∇∇f={\nabla(-f)}\8711; f=\\\8711; f=\∇f=\∇f=∇f、ͮͮ
    ・67917・例)f(x,y)=x 2+y 2 f(x,y)=x^2+y^2 f(x,y)=x 2+y 2,∇f=-(2 x,4 y)-\nablaf=-(2 x,4 y)∇f=-(2 x,4 y)

  • 多変数の場合、微分値の絶対値の代わりにnormでeps条件を設定し、その他は同じ
  • import numpy as np
    import sympy as sym
    from sympy.abc import x
    
    def func(val):
        x_, y_ = val
        func = sym.poly(x**2 + 2*y**3)
        return fun.subs(x,[x_, y_]), fun
    
    def eval_(fun,val):
        val_x, val_y = val
        func_eval = fun.subs(x, val_x).subs(y,val_y)
        return func_eval
    
    def func_gradient(fun,val):
        x_, y_ = val
        _, function = fun(val) #func 함수
        diff_x = sym.diff(function, x)
        diff_y = sym.diff(function, y)
        grad_vec = np.array([eval_(diff_x, [x_,y_]), eval_(diff_y, [x_,y_])])
        return grad_vec, [diff_x, diff_y]
    
    def gradient_descent(fun, init_point, lr_rate = 0.01, epsilon = 0.00001):
        cnt = 0
        val = init_point
        diff, _ = func_gradient(fun, val)
        while np.linalg.norm(diff) > epsilon:
            val = val - lr_rate*diff
            diff, _ = func_gradient(fun, val)
            cnt +=1
        print("함수: {fun(val)[1]}, 연산횟수: {cnt}, chlthwja: ({val}, {fun(val)[0]})"
    
    pt = [np.random.uniform(-2,2), np.random.uniform(-2,2)]
    gradient_descent(fun = func, init_point=pt)