주요 콘텐츠

신경망 ODE를 사용한 동적 시스템 모델링

이 예제에서는 물리 시스템의 동특성을 학습하도록 신경망 상미분 방정식(ODE)을 사용하여 신경망을 훈련시키는 방법을 다룹니다.

신경망 ODE[1]는 ODE의 해에 의해 정의되는 딥러닝 연산입니다. 더 구체적으로, 신경망 ODE는 모든 아키텍처에 사용할 수 있는 연산이며 입력값이 주어지면 그에 따른 출력값이 다음 ODE의 수치 해로 정의됩니다.

y=f(t,y,θ)

이는 시간 지평(horizon) (t0,t1)에서 초기 조건 y(t0)=y0을 갖는 ODE입니다. ODE의 우변 f(t,y,θ)는 모델이 훈련 과정에 학습하는 훈련 가능한 파라미터 세트 θ에 종속됩니다. 이 예제에서 f(t,y,θ)는 완전 연결 연산과 비선형 활성화가 포함된 모델 함수로 모델링됩니다. 초기 조건 y0은 전체 아키텍처의 입력값(이 예제의 경우)이거나 이전의 어떤 연산에서의 출력값입니다.

이 예제에서는 다음 ODE로 설명되는 주어진 물리 시스템의 동특성 x를 학습하도록 신경망 ODE를 갖는 신경망을 훈련시키는 방법을 다룹니다.

x=Ax,

여기서 A는 2×2 행렬입니다.

이 예제의 신경망은 초기 조건을 입력값으로 받고, 학습된 신경망 ODE 모델을 통해 ODE 해를 계산합니다.

초기 조건이 주어지면 신경망 ODE 연산은 ODE 모델의 해를 출력합니다. 이 예제에서는 완전 연결 계층, tanh 계층 및 또 다른 완전 연결 계층을 갖는 블록을 ODE 모델로 지정합니다.

이 예제에서 모델을 정의하는 ODE의 해는 명시적 룽게-쿠타(Explicit Runge-Kutta) (4,5) 도르만드-프린스(Dormand-Prince) 쌍을 사용하여 수치적으로 구해집니다[2]. 역방향 통과는 자동 미분을 사용하여 ODE 솔버의 각 연산을 통해 역전파해 나감으로써 훈련 가능한 파라미터 θ를 학습합니다.

학습된 함수 f(t,y,θ)는 추가적인 초기 조건에 대해 동일한 모델의 해를 구할 때 우변으로 사용됩니다.

목표 동특성 데이터 합성하기

목표 동특성을 초기 조건이 x0인 선형 ODE 모델 x=Ax로 정의하고, 시간 구간 [0 15]에서 ode45를 사용하여 수치 해 xTrain을 계산합니다. 정확한 ground truth 데이터를 계산하기 위해 ode45 수치 솔버의 상대 허용오차를 10-7로 설정합니다. 나중에 신경망 ODE 모델을 사용해 근사된 동특성을 학습할 때 xTrain의 값을 ground truth 데이터로 사용할 수 있습니다.

x0 = [2; 0];
A = [-0.1 -1; 1 -0.1];
trueModel = @(t,y) A*y;

numTimeSteps = 2000;
T = 15;
odeOptions = odeset(RelTol=1.e-7);
t = linspace(0, T, numTimeSteps);
[~, xTrain] = ode45(trueModel, t, x0, odeOptions);
xTrain = xTrain';

훈련 데이터를 플롯에 시각화합니다.

figure
plot(xTrain(1,:),xTrain(2,:))
title("Ground Truth Dynamics") 
xlabel("x(1)") 
ylabel("x(2)")
grid on

모델 파라미터를 정의하고 초기화하기

모델 함수는 dlode45에 대한 한 번의 호출로 구성되며, 이 호출로 40개의 시간 스텝에서 근사 동특성 f(t,y,θ)로 정의된 ODE를 풉니다.

neuralOdeTimesteps = 40;
dt = t(2);
timesteps = (0:neuralOdeTimesteps)*dt;

dlode45 호출에 사용할 학습 가능한 파라미터를 정의하고 이를 변수 neuralOdeParameters에 수집합니다. 함수 initializeGlorot는 학습 가능한 파라미터의 크기 sz와 완전 연결 연산의 출력 개수 및 입력 개수를 입력값으로 받은 다음, Glorot 초기화를 사용하여 설정된 값을 갖는 기본 유형이 single형인 dlarray 객체를 반환합니다. 함수 initializeZeros는 학습 가능한 파라미터의 크기를 입력값으로 받고, 그 파라미터를 기본 유형이 single형인 dlarray 객체로 반환합니다. 초기화 예제 함수는 이 예제에 지원 파일로 첨부되어 있습니다. 이러한 함수에 액세스하려면 이 예제를 라이브 스크립트로 여십시오. 모델 함수의 학습 가능한 파라미터를 초기화하는 방법에 대한 자세한 내용은 Initialize Learnable Parameters for Model Function 항목을 참조하십시오.

파라미터 구조체를 초기화합니다.

neuralOdeParameters = struct;

ODE 모델의 완전 연결 연산에 대한 파라미터를 초기화합니다. 첫 번째 완전 연결 연산은 크기가 stateSize인 벡터를 입력값으로 받고, 그 길이를 hiddenSize로 늘립니다. 반대로, 두 번째 완전 연결 연산은 길이가 hiddenSize인 벡터를 입력값으로 받고, 그 길이를 stateSize로 줄입니다.

stateSize = size(xTrain,1);
hiddenSize = 20;

neuralOdeParameters.fc1 = struct;
sz = [hiddenSize stateSize];
neuralOdeParameters.fc1.Weights = initializeGlorot(sz, hiddenSize, stateSize);
neuralOdeParameters.fc1.Bias = initializeZeros([hiddenSize 1]);

neuralOdeParameters.fc2 = struct;
sz = [stateSize hiddenSize];
neuralOdeParameters.fc2.Weights = initializeGlorot(sz, stateSize, hiddenSize);
neuralOdeParameters.fc2.Bias = initializeZeros([stateSize 1]);

모델의 학습 가능한 파라미터를 표시합니다.

neuralOdeParameters.fc1
ans = struct with fields:
    Weights: [20×2 dlarray]
       Bias: [20×1 dlarray]

neuralOdeParameters.fc2
ans = struct with fields:
    Weights: [2×20 dlarray]
       Bias: [2×1 dlarray]

신경망 ODE 모델 정의하기

이 예제의 ODE 모델 섹션에 나와 있는 함수 odeModel을 만듭니다. 이 함수는 시간 입력값(사용되지 않음)과 그에 대응하는 해, 그리고 ODE 함수 파라미터를 입력값으로 받습니다. 이 함수는 파라미터로 지정된 가중치와 편향을 사용하여 완전 연결 연산과 tanh 연산 및 또 다른 완전 연결 연산을 입력 데이터에 적용합니다.

모델 함수 정의하기

이 예제의 모델 함수 섹션에 나와 있는 함수 model을 만듭니다. 이 함수는 딥러닝 모델의 출력값을 계산합니다. 함수 model은 모델 파라미터와 입력 데이터를 입력값으로 받습니다. 이 함수는 신경망 ODE의 해를 출력합니다.

모델 손실 함수 정의하기

이 예제의 모델 손실 함수 섹션에 나와 있는 함수 modelLoss를 만듭니다. 이 함수는 모델 파라미터와 입력 데이터 및 이에 대응하는 목표값으로 구성된 미니 배치를 입력값으로 받고, 손실과 학습 가능한 파라미터에 대한 해당 손실의 기울기를 반환합니다.

훈련 옵션 지정하기

Adam 최적화에 대한 옵션을 지정합니다.

gradDecay = 0.9;
sqGradDecay = 0.999;
learnRate = 0.002;

크기가 200인 미니 배치를 사용하여 훈련을 1200번 반복합니다.

numIter = 1200;
miniBatchSize = 200;

50회 반복마다 학습된 동특성의 해를 구하고, 이를 위상 다이어그램에 ground truth와 함께 나타내어 훈련 경로를 표시합니다.

plotFrequency = 50;

사용자 지정 훈련 루프를 사용하여 모델 훈련시키기

Adam 솔버에 대한 averageGrad 파라미터와 averageSqGrad 파라미터를 초기화합니다.

averageGrad = [];
averageSqGrad = [];

TrainingProgressMonitor 객체를 초기화합니다. monitor 객체를 생성할 때 타이머가 시작되므로 이 객체를 훈련 루프와 가깝게 생성해야 합니다.

monitor = trainingProgressMonitor(Metrics="Loss",Info=["Iteration","LearnRate"],XLabel="Iteration");

사용자 지정 훈련 루프를 사용하여 신경망을 훈련시킵니다.

각 반복에 대해 다음을 수행합니다.

  • 이 예제의 미니 배치 함수 만들기 섹션에 나와 있는 createMiniBatch 함수를 사용하여 합성 데이터로부터 미니 배치를 생성합니다.

  • 이 예제의 모델 손실 함수 섹션에 나와 있는 dlfeval 함수와 modelLoss 함수를 사용하여 모델 손실과 모델 기울기를 평가합니다.

  • adamupdate 함수를 사용하여 모델 파라미터를 업데이트합니다.

  • 훈련 진행 상황 플롯을 업데이트합니다.

numTrainingTimesteps = numTimeSteps;
trainingTimesteps = 1:numTrainingTimesteps;
plottingTimesteps = 2:numTimeSteps;

iteration = 0;

while iteration < numIter && ~monitor.Stop
    iteration = iteration + 1;

    % Create batch
    [X, targets] = createMiniBatch(numTrainingTimesteps, neuralOdeTimesteps, miniBatchSize, xTrain);

    % Evaluate network and compute loss and gradients
    [loss,gradients] = dlfeval(@modelLoss,timesteps,X,neuralOdeParameters,targets);

    % Update network
    [neuralOdeParameters,averageGrad,averageSqGrad] = adamupdate(neuralOdeParameters,gradients,averageGrad,averageSqGrad,iteration,...
        learnRate,gradDecay,sqGradDecay);

    % Plot loss
    recordMetrics(monitor,iteration,Loss=loss);

    % Plot predicted vs. real dynamics
    if mod(iteration,plotFrequency) == 0  || iteration == 1

        % Use ode45 to compute the solution 
        y = dlode45(@odeModel,t,dlarray(x0),neuralOdeParameters,DataFormat="CB");

        plot(xTrain(1,plottingTimesteps),xTrain(2,plottingTimesteps),"r--")

        hold on
        plot(y(1,:),y(2,:),"b-")
        hold off

        xlabel("x(1)")
        ylabel("x(2)")
        title("Predicted vs. Real Dynamics")
        legend("Training Ground Truth", "Predicted")

        drawnow
    end
    updateInfo(monitor,Iteration=iteration,LearnRate=learnRate);
    monitor.Progress = 100*iteration/numIter;
end

모델 평가하기

모델을 사용하여 서로 다른 초기 조건으로 근사해를 구합니다.

모델 훈련에 사용된 초기 조건과는 다른 새 초기 조건 4개를 정의합니다.

tPred = t;

x0Pred1 = sqrt([2;2]);
x0Pred2 = [-1;-1.5];
x0Pred3 = [0;2];
x0Pred4 = [-2;0];

4개의 새 초기 조건에 대해 ode45를 사용하여 ODE의 실제 동특성의 해를 수치적으로 구합니다.

[~, xTrue1] = ode45(trueModel, tPred, x0Pred1, odeOptions);
[~, xTrue2] = ode45(trueModel, tPred, x0Pred2, odeOptions);
[~, xTrue3] = ode45(trueModel, tPred, x0Pred3, odeOptions);
[~, xTrue4] = ode45(trueModel, tPred, x0Pred4, odeOptions);

학습된 신경망 ODE 동특성을 사용하여 수치적으로 ODE를 풉니다.

xPred1 = dlode45(@odeModel,tPred,dlarray(x0Pred1),neuralOdeParameters,DataFormat="CB");
xPred2 = dlode45(@odeModel,tPred,dlarray(x0Pred2),neuralOdeParameters,DataFormat="CB");
xPred3 = dlode45(@odeModel,tPred,dlarray(x0Pred3),neuralOdeParameters,DataFormat="CB");
xPred4 = dlode45(@odeModel,tPred,dlarray(x0Pred4),neuralOdeParameters,DataFormat="CB");

예측 시각화하기

이 예제의 실제 해 및 예측 해 함수 플로팅하기 섹션에 나와 있는 함수 plotTrueAndPredictedSolutions를 사용해 다양한 초기 조건에서 예측 해와 ground truth 해를 비교하여 시각화합니다.

figure
subplot(2,2,1)
plotTrueAndPredictedSolutions(xTrue1, xPred1);
subplot(2,2,2)
plotTrueAndPredictedSolutions(xTrue2, xPred2);
subplot(2,2,3)
plotTrueAndPredictedSolutions(xTrue3, xPred3);
subplot(2,2,4)
plotTrueAndPredictedSolutions(xTrue4, xPred4);

헬퍼 함수

모델 함수

예측에 사용되는 신경망을 정의하는 model 함수는 한 번의 신경망 ODE 호출로 구성됩니다. 각 관측값에 대해, 이 함수는 수치 해의 출력 시점을 정의하는 시간 지점으로 구성된 벡터 tspan과 더불어 길이가 stateSize인 벡터를 입력값으로 받습니다. 이 벡터는 함수 odeModel을 ODE의 우변으로 사용하여 해를 수치적으로 구할 때 초기 조건으로 사용됩니다. odeModel 함수는 풀려는 ODE의 학습 가능한 우변 f(t,y,θ)를 나타냅니다. 학습된 시스템이 자율 시스템이기 때문에 이 함수는 초기 조건에 관계없이 각 관측값에 벡터 tspan을 사용합니다. 즉, odeModel 함수는 시간에 명시적으로 종속되지 않습니다.

function X = model(tspan,X0,neuralOdeParameters)

X = dlode45(@odeModel,tspan,X0,neuralOdeParameters,DataFormat="CB");

end

ODE 모델

odeModel 함수는 dlode45 호출에 사용되는 학습 가능한 우변입니다. 이 함수는 크기가 stateSize인 벡터를 입력값으로 받고, 길이가 hiddenSize가 되도록 벡터를 확대한 다음, 비선형 함수 tanh를 적용합니다. 그런 다음 길이가 stateSize가 되도록 벡터를 다시 압축합니다.

function y = odeModel(~,y,theta)

y = tanh(theta.fc1.Weights*y + theta.fc1.Bias);
y = theta.fc2.Weights*y + theta.fc2.Bias;

end

모델 손실 함수

이 함수는 벡터 tspan과 초기 조건 X0 세트, 학습 가능한 파라미터 neuralOdeParameters 및 목표값 시퀀스 targets를 입력값으로 받습니다. 그리고 model 함수를 사용하여 예측값을 계산하고 이를 주어진 목표값 시퀀스와 비교합니다. 마지막으로, 손실과 신경망 ODE의 학습 가능한 파라미터에 대한 손실 기울기를 계산합니다.

function [loss,gradients] = modelLoss(tspan,X0,neuralOdeParameters,targets)

% Compute predictions.
X = model(tspan,X0,neuralOdeParameters);

% Compute L1 loss.
loss = l1loss(X,targets,NormalizationFactor="all-elements",DataFormat="CBT");

% Compute gradients.
gradients = dlgradient(loss,neuralOdeParameters);

end

미니 배치 함수 만들기

createMiniBatch 함수는 목표 동특성에 대한 관측값으로 구성된 배치를 만듭니다. 이 함수는 ground truth 데이터의 총 시간 스텝 수 numTimesteps와 각 관측값에 대해 반환될 연속된 시간 스텝 수 numTimesPerObs, 관측값 개수 miniBatchSize, ground truth 데이터 X를 입력값으로 받습니다.

function [x0, targets] = createMiniBatch(numTimesteps,numTimesPerObs,miniBatchSize,X)

% Create batches of trajectories.
s = randperm(numTimesteps - numTimesPerObs, miniBatchSize);

x0 = dlarray(X(:, s));
targets = zeros([size(X,1) miniBatchSize numTimesPerObs]);

for i = 1:miniBatchSize
    targets(:, i, 1:numTimesPerObs) = X(:, s(i) + 1:(s(i) + numTimesPerObs));
end

end

실제 해 및 예측 해 함수 플로팅하기

plotTrueAndPredictedSolutions 함수는 실제 해 xTrue와 학습된 신경망 ODE 모델로 구한 근사해 xPred, 그리고 그에 대응되는 초기 조건 x0Str을 입력값으로 받습니다. 이 함수는 실제 해와 예측 해 사이의 오차를 계산하고, 이를 위상 다이어그램에 플로팅합니다.

function plotTrueAndPredictedSolutions(xTrue,xPred)

xPred = squeeze(xPred)';

err = mean(abs(xTrue(2:end,:) - xPred), "all");

plot(xTrue(:,1),xTrue(:,2),"r--",xPred(:,1),xPred(:,2),"b-",LineWidth=1)

title("Absolute Error = " + num2str(err,"%.4f"))
xlabel("x(1)")
ylabel("x(2)")

xlim([-2 3])
ylim([-2 3])

legend("Ground Truth","Predicted")

end

[1] Chen, Ricky T. Q., Yulia Rubanova, Jesse Bettencourt, and David Duvenaud. “Neural Ordinary Differential Equations.” Preprint, submitted December 13, 2019. https://arxiv.org/abs/1806.07366.

[2] Shampine, Lawrence F., and Mark W. Reichelt. “The MATLAB ODE Suite.” SIAM Journal on Scientific Computing 18, no. 1 (January 1997): 1–22. https://doi.org/10.1137/S1064827594276424.

Copyright 2021–2023 The MathWorks, Inc.

참고 항목

| | | |

도움말 항목