줄리아 플럭스에서 MLP 구현해서 비선형함수 근사하는 방법
시작
using Flux
using Plots
using Distributions
using Flux: @epochs
function f(x)
if -5 ≤ x < -2
y = -3x + 2
elseif -2 ≤ x < 1
y = x + 10
elseif 1 ≤ x < 2
y = -2x + 13
elseif 2 ≤ x < 3
y = 4x + 1
elseif 3 ≤ x ≤ 5
y = -4x + 25
end
return y
end
x_ = -5:0.01:5
y_ = f.(x_)
plot(x_, y_)
필요한 패키지를 불러오고, 우리가 근사하고 싶은 비선형함수를 정의하자.
학습집합 생성
julia> Data = convert.(Float32, rand(Uniform(-5,5), 1024))
1024-element Vector{Float32}:
julia> Data = convert(Matrix, reshape(Data, (1,1024)))
1×1024 Matrix{Float32}:
함수의 정의역인 $[-5, 5]$에서 임의의 점 1024개를 뽑았다. 이렇게 뽑으면 자료형이 Float64
인데, 딥러닝에서는 기본적으로 Float32
자료형을 다루므로 바꿔주었다. 물론 자료형이 Float64
나 Int64
인 데이터를 모델에 인풋으로 써도 알아서 자료형을 바꾸고 실행하기는 한다.
또한 각각의 열이 하나의 데이터를 의미하기 때문에(이해가 안된다면 행렬의 곱을 생각해보라) 1024-벡터를 1x1024 매트릭스로 바꿔주었다.
Label = f.(Data)
Train_Set = Flux.DataLoader((Data, Label), batchsize=128)
위에서 정의한 함수 $f$로 레이블을 만들고, Flux.DataLoader
로 훈련에 사용할 수 있게 만들었다.
모델 정의
model = Chain(
Dense(1,5, relu),
Dense(5,5, relu),
Dense(5,1)
)
x_input = reshape(x_, (1,1001))
x_input = convert(Matrix{Float32}, x_input)
ŷ = model(x_input)
plot(vec(x_input), vec(ŷ))
Chain()
으로 MLP를 만들고, 함수의 그래프를 그려보면 $f$와 전혀 다름을 확인할 수 있다.
손실함수와 옵티마이저 정의
LOSS(x,y) = Flux.mse(model(x), y)
opt = ADAM()
손실함수는 MSE, 옵티마이저는 ADAM으로 정의했다.
훈련
julia> @epochs 5000 @time Flux.train!(LOSS, Flux.params(model), Train_Set, opt,
cb = Flux.throttle(() -> @show(LOSS(Data, Label)), 1))
[ Info: Epoch 5000
LOSS(Data, Label) = 1.3867694f-6
0.001494 seconds (3.04 k allocations: 549.953 KiB)
이제 @epochs
매크로로 훈련시킬 수 있다. 5000 에포크를 반복한 후, 로스가 아주 작아진 것을 확인할 수 있다.
MLP의 그래프를 그려보면 다음과 같다.
ŷ = model(x_input)
plot(vec(x_input), vec(ŷ))
코드 전문
using Flux
using Plots
using Distributions
using Flux: @epochs
function f(x)
if -5 ≤ x < -2
y = -3x + 2
elseif -2 ≤ x < 1
y = x + 10
elseif 1 ≤ x < 2
y = -2x + 13
elseif 2 ≤ x < 3
y = 4x + 1
elseif 3 ≤ x ≤ 5
y = -4x + 25
end
return y
end
x_ = -5:0.01:5
y_ = f.(x_)
plot(x_, y_)
savefig("nonlinear_function.png")
Data = convert.(Float32, rand(Uniform(-5,5), 1024))
Data = convert(Matrix, reshape(Data, (1,1024)))
Label = f.(Data)
Train_Set = Flux.DataLoader((Data, Label), batchsize=128)
model = Chain(
Dense(1,5, relu),
Dense(5,5, relu),
Dense(5,1)
)
x_input = reshape(x_, (1,1001))
x_input = convert(Matrix{Float32}, x_input)
ŷ = model(x_input)
plot(vec(x_input), vec(ŷ))
savefig("initial_MLP.png")
LOSS(x,y) = Flux.mse(model(x), y)
opt = ADAM()
@epochs 5000 @time Flux.train!(LOSS, Flux.params(model), Train_Set, opt, cb = Flux.throttle(() -> @show(LOSS(Data, Label)), 1))
ŷ = model(x_input)
plot(vec(x_input), vec(ŷ))
savefig("trained_MLP.png")
환경
- OS: Windows10
- Version: Julia 1.7.1, Flux 0.12.8