LoginSignup
1
0

More than 3 years have passed since last update.

勾配法で2次関数の最大値・最小値を求める

Posted at

勾配法を利用して、1次関数の最大値・最小値を探索し図示、またイテレーションの推移をグラフ化する。このプログラムは、ニューラルネットワークを学んでいる最中に作ったプログラムであり、あえてライブラリを使っていない部分がある。

#勾配法を使って1変数関数の最大値・最小値を探索、イテレーションの推移をグラフ化
import numpy as np
import matplotlib.pyplot as plt

def function_3(x):
    return -x**2 + 5

def function_4(x):
    return -x**3 - 4*x**2 + 4*x + 10

# 数値微分
def numerical_diff(f, x):
    h = 1e-4 # 0.0001
    diff = (f(x+h)-f(x-h)) / (2*h)
    return diff

#勾配法で最小値、最大値を求める
def grad_descent_1(f, init_x, lr, steps):
    x = init_x
    grads = numerical_diff(f, x)

    if grads >= 0:
        for _ in range(steps):
            grads = numerical_diff(f, x)
            x -= lr*grads

        print('最小値:')
        return f(x)

    elif grads < 0:
        for _ in range(steps):
            grads = numerical_diff(f, x)
            x += lr*grads

        print('最大値:')
        return f(x)

# グラフ用
def grad_descent_2(f, init_x, lr, steps):
    lr = lr
    steps = steps
    x = init_x
    grads = numerical_diff(f, x)

    if grads >= 0:
        while True:
            grads = numerical_diff(f, x)
            x -= lr*grads

            yield x

    elif grads < 0:
        while True:
            grads = numerical_diff(f, x)
            x += lr*grads

            yield x

#関数の概形と現在位置、最小値を表示
def graph(f, init_x, x):
    init_y = f(init_x)
    y = f(x) #関数の設定
    plt.figure()

    def start_point(init_x):
        plt.plot(init_x, init_y, 'o', label="start", color='blue')

    start_point(init_x) #始点を表示
    plt.plot(x, y, label="x**2 + 5") #グラフを表示
    plt.plot(linear_grad, 'o', label="min") #最小点
    plt.legend() # 凡例をグラフにプロット
    plt.grid(which='both', axis = "both", linewidth =1)
    plt.show()

#最大値・最小値に収束していく様子をグラフ化
def visualize(f):
    grad = grad_descent_2(f, init_x=init_x, lr=lr, steps=steps)
    x = range(steps)
    y = [next(grad) for j in x] #gradsを配列に格納

    fig = plt.figure()
    ax = plt.axes()
    ax.set_xlabel("steps")
    ax.set_ylabel("x")
    plt.title("勾配法による収束過程")
    plt.plot(x, y)
    plt.show()


x = np.arange(-4, 6, 0.1)
func = function_3
init_x = 3.0
lr = 0.01
steps = 300
linear_grad = grad_descent_1(func, init_x=init_x, lr=lr, steps=steps)
print(linear_grad)

graph(func, init_x=init_x, x=x)
visualize(func)

# 最大値:4.99995103475578

2次関数の場合、
スクリーンショット 2019-07-19 07.14.17.png
となり、始点と最大値が図示される。また、イテレーションの収束過程は、
スクリーンショット 2019-07-19 07.25.30.png
となり、収束していることが分かる。最小値の場合も、

# 最小値:-4.99995103475578

となり、
スクリーンショット 2019-07-19 07.33.26.png スクリーンショット 2019-07-19 07.42.10.png
最小値が図示される。
では、3次関数の場合だと、

# 最大値:10.900894327379042

スクリーンショット 2019-07-19 07.47.38.png スクリーンショット 2019-07-19 07.47.45.png
きちんと動作している。

参考文献
オライリー・ジャパン ゼロから作るDeepLearning 斎藤康毅 著

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0