Lua판 제로로부터 만드는 Deep Learning 그 12[구배법]
과거 기사 요약
Lua판 제로로부터 만드는 Deep Learning 정리
소개
이번은 원서 4장의 구배법의 부분을 실장합니다. 우선 스크립트는 다음과 같습니다.
gradient_method.lua
require 'gnuplot'
require './gradient_2d.lua'
---勾配探索関数.
-- 与えられた関数と初期値で勾配を計算し、最終的な値とステップごとの勾配の値を返す。
-- @param f 入力値 (Type:function)
-- @param init_x 初期値 (Type:1D Tensor)
-- @param lr 学習率 (Type:number [default : 0.01])
-- @param step_num 最大ステップ数 (Type:number [default : 100])
-- @return 最終的な値, ステップごとの関数の値 (Type:1D Tensor, Tensor)
function gradient_descent(f, init_x, lr, step_num)
--デフォルト引数
if not lr then lr = 0.01 end
if not step_num then step_num = 100 end
local x = init_x:clone() -- x = init_x は参照渡しになるので代わりにコピーを渡す
local x_history = {}
for i = 1, step_num do
table.insert(x_history, torch.totable(x:clone()))
grad = numerical_gradient(f, x)
x:csub(lr * grad)
end
return x, torch.Tensor(x_history):t()
end
---(Σxi^2)他変数関数.
-- @param x 入力値 (Type:Tensor)
-- @return 出力値 (Type:Tensor)
function function_2(x)
if x:dim() == 1 then
return torch.sum(torch.pow(x,2))
else
return torch.sum(torch.pow(x,2), 2)
end
end
local init_x = torch.Tensor({-3.0, 4.0})
local lr = 0.1
local step_num = 100
local x, x_history = gradient_descent(function_2, init_x, lr, step_num)
print(x)
--学習率が大きすぎる場合 lr = 10.0
lr = 10.0
x, x_history = gradient_descent(function_2, init_x, lr, step_num)
print(x)
--学習率が小さすぎる場合 lr = 1e-10
lr = 1e-10
x, x_history = gradient_descent(function_2, init_x, lr, step_num)
print(x)
--学習遷移を図示
lr = 0.1
step_num = 20
x, x_history = gradient_descent(function_2, init_x, lr, step_num)
gnuplot.figure(1)
gnuplot.axis({-3, 3, -4, 4})
gnuplot.xlabel("x0")
gnuplot.ylabel("x1")
gnuplot.plot({x_history[1], x_history[2], '+'})
gradient_2d.lua에는 이전에 구현한 그라디언트 계산 함수가 들어 있습니다. 중복되지만 다시 제시하면 다음과 같습니다.
gradient_2d.lua
---勾配算出関数.
-- 入力値に対する多変数関数の勾配を求める
-- @param f 多変数関数 (Type:function)
-- @param x 入力値 (Type:Tensor ※1D Tensor)
-- @return 入力値に対する勾配の値 (Type:Tensor)
function _numerical_gradient_no_batch(f, x)
local h = 1e-4 -- 0.0001
grad = x:clone():zero()
for idx = 1, x:size()[1] do
local tmp_val = x:float()[idx]
x[idx] = tmp_val + h --一つの要素だけ動かす
local fxh1 = f(x) -- f(x+h)
x[idx] = tmp_val - h
local fxh2 = f(x) -- f(x-h)
grad[idx] = (fxh1 - fxh2) / (2*h)
x[idx] = tmp_val -- 値を元に戻す
end
return grad
end
---勾配算出関数.
-- 入力値(複数)に対する多変数関数の勾配を求める
-- @param f 多変数関数 (Type:function)
-- @param x 入力値 (Type:Tensor)
-- @return 入力値に対する勾配の値 (Type:Tensor)
function numerical_gradient(f, X)
if X:dim() == 1 then
return _numerical_gradient_no_batch(f, X)
else
local grad = X:clone():zero()
for idx = 1, X:size()[1] do
grad[idx] = _numerical_gradient_no_batch(f, X[idx]) --1Dずつ勾配を計算
end
return grad
end
end
이 실행 결과는 다음과 같습니다.
실행 결과
$ th gradient_method.lua
1e-10 *
-6.1111
8.1481
[torch.DoubleTensor of size 2]
-2.5898e+13
-1.2950e+12
[torch.DoubleTensor of size 2]
-3.0000
4.0000
[torch.DoubleTensor of size 2]
그래프의 결과는 다음과 같습니다.
꽤 파이썬과 다르지 않은 구현이 가능했습니다.
특히 설명을 요하는 어려운 부분은 없습니다만, 뭔가의 주의점을 말한다고 한다면 numpy 배열과 달리, Tensor의 대입은 기본적으로 참조 전달을 의미하는 점에 주의해 주세요. :clone()로 복사본을 전달하는 것이 안전합니다.
이런 일은 테이블형 {}에도 같은 것을 말할 수 있습니다. Lua에 익숙하지 않다면 실수로 잡힐 수 있으므로주의가 필요합니다.
결론
이번은 이상입니다.
다음 번에는 신경망으로 돌아가 손실 함수의 기울기를 구해 보겠습니다.
고맙습니다.
Reference
이 문제에 관하여(Lua판 제로로부터 만드는 Deep Learning 그 12[구배법]), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/Kazuki-Nakamae/items/2a67c3979e38eb43bfaa텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)