「大人の教養・知識・気付き」を伸ばすブログ

一流の大人(ビジネスマン、政治家、リーダー…)として知っておきたい、教養・社会動向を意外なところから取り上げ学ぶことで“気付く力”を伸ばすブログです。データ分析・語学に力点を置いています。 →現在、コンサルタントの雛になるべく、少しずつ勉強中です(※2024年1月21日改訂)。

MENU

Juliaを使ってみる(03/22):最適化

1. 1変数の最適化

# 1変数関数の最適化
function gradient_method_1dim(f,x_init,eta,maxiter)
    # 最適化過程のパラメータを格納する配列
    x_seq = Array{typeof(x_init),1}(undef, maxiter) # p.63
    
    # 勾配
    f_prime(x)= ForwardDiff.derivative(f, x)
    
    # 初期値の設定
    x_seq[1] = x_init
    
    # メインの最適化ループ
    for i in 2:maxiter
        x_seq[i] = x_seq[i-1] + eta * f_prime(x_seq[i-1])
    end
    
    x_seq
end

####################
### 最適化の実施 ###
####################

# 初期値の設定
x_init = -2.5

# 探索の繰り返し数
maxiter = 200

# ステップサイズ
eta = 0.05

# 最適化計算を実施
x_seq = gradient_method_1dim(f, x_init, eta, maxiter)
f_seq = f.(x_seq)

# 最適化過程の可視化
fig, ax = subplots(figsize = (8,3))
ax.plot(f_seq)
ax.set_xlabel("iteration"), ax.set_ylabel("f")
ax.grid()

fig, axes = subplots(1,2,figsize=(8,3))

# 関数のプロット
axes[1].plot(xs, f.(xs), label = "function")

# 探索の過程
axes[1].plot(x_seq, f.(x_seq), "bx", label = "sequence")

# 最適値
axes[1].plot(x_opt, f(x_opt), "rx", label = "optimal")
axes[1].set_xlabel("x"), axes[1].set_ylabel("y")
axes[1].grid()
axes[1].legend()

# 探索の過程をステップごとにプロット
axes[2].plot(1:maxiter, x_seq, "bx-", label = "sequence")
axes[2].hlines(x_opt, 0, maxiter, ls = "--", label = "x_opt")
axes[2].set_xlim([0,maxiter])
axes[2].set_xlabel("iteration"), axes[2].set_ylabel("x")
axes[2].grid()
axes[2].legend()

tight_layout()

2. 多変数の最適化

2.1 2変数関数の定義

# 2変数関数を定義
x_opt = [0.50, 0.25]
f_2(x) = -sqrt(0.05 + (x[1] - x_opt[1])^2) - (x[2] - x_opt[2])^2

# 関数を等高線図として可視化
L = 500
xs1 = range(-1, 1, length = L)
xs2 = range(-1, 1, length = L)
fig, ax = subplots()
ax.contour(xs1, xs2, [f_2([x1, x2]) for x1 in xs1, x2 in xs2]')
ax.plot(x_opt[1], x_opt[2], color = "r", marker = "x", label = "optimal")
ax.set_xlabel("x1"), ax.set_ylabel("x2")
ax.grid()
ax.legend()


2.2 多変数関数の最適化

##########################
### 多変数関数の勾配法 ###
##########################

function gradient_method(f, x_init, eta, maxiter)
    # 最適化過程のパラメータを格納する配列
    x_seq = Array{typeof(x_init[1]),2}(undef, length(x_init), maxiter)
    
    # 勾配
    grad_f(x) = ForwardDiff.gradient(f, x)
    
    # 初期値
    x_seq[:,1] = x_init
    
    # 主要の最適化ループ
    for i in 2:maxiter
        x_seq[:, i] = x_seq[:, i-1] + eta * grad_f(x_seq[:,i-1])
    end
    
    x_seq
end

# パラメータの設定
x_init = [-0.75, -0.75]
maxiter = 500
eta = 0.01

# 最適化の実施
x_seq = gradient_method(f_2, x_init, eta, maxiter)
f_seq = [f_2(x_seq[:,i]) for i in 1:maxiter]

# 目的関数の値をステップごとにプロットする
fig, ax = subplots(figsize = (8,3))
ax.plot(f_seq)
ax.set_xlabel("iteration"), ax.set_ylabel("f")
ax.grid()

fig, axes = subplots(1, 2, figsize = (8,3))

# 等高線図で関数を可視化
axes[1].contour(xs1, xs2, [f_2([x1, x2]) for x1 in xs1, x2 in xs2]')

# 最適化の過程
axes[1].plot(x_seq[1,:], x_seq[2,:], ls = "--", marker = "x", label = "sequence")
axes[1].plot(x_opt[1], x_opt[2], color = "r", marker = "x", label = "optimal")
axes[1].set_xlabel("x1"), axes[1].set_ylabel("x2")
axes[1].grid()
axes[1].legend()

# ステップごとの最適化の過程
axes[2].plot(1:maxiter, x_seq[1,:], color = "b", marker = "o", label = "x[1]")
axes[2].plot(1:maxiter, x_seq[2,:], color = "r", marker = "^", label = "x[2]")
axes[2].hlines(x_opt[1], 0 , maxiter, color = "b", ls = "--", label = "x_opt[1]")
axes[2].hlines(x_opt[2], 0 , maxiter, color = "r", ls = "-.", label = "x_opt[2]")
axes[2].set_xlabel("iteration")
axes[2].set_ylabel("x1, x2")
axes[2].grid()
axes[2].legend()

tight_layout()


プライバシーポリシー お問い合わせ