Main Content

이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.

강화 학습을 사용하여 PI 제어기 조정하기

이 예제에서는 TD3(Twin-Delayed Deep Deterministic: 트윈 지연 심층 결정적) 정책 경사법 강화 학습 알고리즘을 사용하여 PI 제어기의 2가지 이득을 조정하는 방법을 보여줍니다. 조정된 제어기의 성능은 제어 시스템 조정기 앱을 사용하여 조정된 제어기의 성능과 비교됩니다. Simulink®에서 제어 시스템 조정기 앱을 사용하여 제어기를 조정하려면 Simulink Control Design™이 필요합니다.

조정 가능형 파라미터 수가 적어 비교적 간단한 제어 작업의 경우 모델 기반 조정 기법을 사용하면 모델이 주어지지 않은(model-free) RL 기반 방법보다 조정 처리가 더 빠르며 좋은 결과를 얻을 수 있습니다. 하지만 상당히 비선형적인 시스템이나 적응형 제어기 조정 작업에는 RL 방법이 더 적절할 수 있습니다. 제어기 비교가 용이하도록 두 조정 방법에는 선형 2차 가우스(LQG) 목적 함수가 사용됩니다. DDPG 에이전트를 사용하여 LQR 제어기를 구현하는 예제는 Compare DDPG Agent to LQR Controller 항목을 참조하십시오.

이 예제에서는 강화 학습(RL) 에이전트를 사용하여 PI 제어기에 대한 이득을 계산합니다. PI 제어기를 신경망 제어기로 바꾸는 예제는 Simulink 환경 만들기 및 에이전트 훈련시키기 항목을 참조하십시오.

환경 모델

이 예제의 환경 모델은 물탱크 모델입니다. 이 제어 시스템의 목표는 탱크에 있는 물의 수위를 기준 값과 일치하도록 유지하는 것입니다.

open_system('watertankLQG')

모델에는 분산 E(n2(t))=1을 갖는 공정 잡음이 포함되어 있습니다.

물의 수위를 유지하면서도 제어 노력 u를 최소화하기 위해 이 예제의 제어기에는 다음 LQG 기준이 사용됩니다.

J=limTE(1T0T((Href-y(t))2+0.01u2(t))dt)

이 모델에서 제어기를 시뮬레이션하기 위해, 시뮬레이션 시간 Tf와 제어기 샘플 시간 Ts를 초 단위로 지정합니다.

Ts = 0.1;
Tf = 10;

물탱크 모델에 대한 자세한 내용은 watertank Simulink 모델 (Simulink Control Design) 항목을 참조하십시오.

제어 시스템 조정기를 사용하여 PI 제어기 조정하기

Simulink에서 제어 시스템 조정기를 사용하여 제어기를 조정하려면, 제어기 블록을 조정 블록으로 지정하고 조정 프로세스의 목표를 정의해야 합니다. 제어 시스템 조정기 사용 방법에 대한 자세한 내용은 Tune a Control System Using Control System Tuner (Simulink Control Design) 항목을 참조하십시오.

이 예제에서는 저장된 세션 ControlSystemTunerSession.mat제어 시스템 조정기를 사용하여 엽니다. 이 세션에는 watertankLQG의 PID Controller 블록이 조정 블록으로 지정되고 LQG 조정 목표가 포함되어 있습니다.

controlSystemTuner("ControlSystemTunerSession")

제어기를 조정하려면 조정 탭에서 조정을 클릭합니다.

조정된 비례 이득과 적분 이득은 대략적으로 각각 9.8과 1e-6입니다.

Kp_CST = 9.80199999804512;
Ki_CST = 1.00019996230706e-06;

에이전트 훈련을 위한 환경 만들기

RL 에이전트 훈련을 위한 모델을 정의하려면 다음 단계에 따라 물 탱크 모델을 수정하십시오.

  1. PID 제어기를 삭제합니다.

  2. RL Agent 블록을 삽입합니다.

  3. 관측값 벡터 [e dte]T 를 만듭니다. 여기서 e=Href-h이고, h는 탱크의 수위이며, Href는 기준 수위입니다. RL Agent 블록에 관측값 신호를 연결합니다.

  4. RL 에이전트의 보상 함수를 LQG 비용의 음수로 정의합니다. 즉, Reward=-((Href-h(t))2+0.01u2(t))입니다. RL 에이전트는 이 보상을 최대화하므로 LQG 비용을 최소화합니다.

결과로 생성되는 모델은 rlwatertankPIDTune.slx입니다.

mdl = 'rlwatertankPIDTune';
open_system(mdl)

환경 인터페이스 객체를 만듭니다. 이를 위해, 이 예제 끝에 정의된 localCreatePIDEnv 함수를 사용합니다.

[env,obsInfo,actInfo] = localCreatePIDEnv(mdl);

이 환경에 대한 관측값 및 행동 차원을 추출합니다. prod(obsInfo.Dimension)prod(actInfo.Dimension)을 사용하여 행 벡터, 열 벡터 또는 행렬로 정렬되는지에 관계없이 각각 관측값 공간과 행동 공간의 차원 수를 반환합니다.

numObs = prod(obsInfo.Dimension);
numAct = prod(actInfo.Dimension);

재현이 가능하도록 난수 생성기 시드값을 고정합니다.

rng(0)

TD3 에이전트 만들기

액터를 만들려면 먼저 관측값 입력값과 행동 출력값을 갖는 심층 신경망을 만드십시오. 자세한 내용은 rlContinuousDeterministicActor 항목을 참조하십시오.

PI 제어기를 하나의 완전 연결 계층을 가지며 오차와 오차 적분 관측값을 사용하는 신경망으로 모델링할 수 있습니다.

u=[edte]*[KiKp]T

여기서 각 요소는 다음과 같습니다.

  • u는 액터 신경망의 출력값입니다.

  • KpKi는 신경망 가중치의 절댓값입니다.

  • e=Href-h(t)이고, h(t)는 탱크의 높이이며, Href는 기준 높이입니다.

경사하강법 최적화에서는 가중치가 음수 값이 될 수 있습니다. 음수 가중치를 피하려면 표준 fullyConnectedLayerfullyConnectedPILayer로 바꾸십시오. 이 계층은 함수 Y=abs(WEIGHTS)*X를 구현하여 가중치가 양수가 되도록 하며, 파일 fullyConnectedPILayer.m에 정의되어 있습니다. 이 파일은 MATLAB 검색 경로에 있거나 이 에이전트가 사용될 때 현재 폴더에 있어야 합니다. 사용자 지정 계층 정의에 대한 자세한 내용은 사용자 지정 딥러닝 계층 정의하기 항목을 참조하십시오.

initialGain = single([1e-3 2]);

actorNet = [
    featureInputLayer(numObs)
    fullyConnectedPILayer(initialGain,'ActOutLyr')
    ];

actorNet = dlnetwork(actorNet);


actor = rlContinuousDeterministicActor(actorNet,obsInfo,actInfo);

이 예제의 에이전트는 TD3(트윈 지연 심층 결정적) 정책 경사법 에이전트입니다. TD3 에이전트는 최적의 정책을 학습하기 위해 액터 및 크리틱 근사기 객체에 의존합니다.

TD3 에이전트는 관측값과 행동이 주어지면 2개의 크리틱 가치 함수 표현을 사용하여 장기 보상을 근사합니다. 크리틱을 만들려면 먼저 관측값과 행동에 해당하는 2개의 입력값 및 1개의 출력값을 갖는 심층 신경망을 만드십시오.

크리틱을 만들려면 이 예제 끝에 정의된 localCreateCriticNetwork 함수를 사용합니다. 두 크리틱 표현에 동일한 신경망 구조를 사용합니다.

criticNet = localCreateCriticNetwork(numObs,numAct);

지정된 신경망과 환경 행동 및 관측값 사양을 사용하여 critic 객체를 만듭니다. 관측값 채널 및 행동 채널과 연결할 신경망 계층의 이름도 추가 인수로 전달합니다.

critic1 = rlQValueFunction(dlnetwork(criticNet), ...
    obsInfo,actInfo,...
    ObservationInputNames='stateInLyr', ...
    ActionInputNames='actionInLyr');

critic2 = rlQValueFunction(dlnetwork(criticNet), ...
    obsInfo,actInfo,...
    ObservationInputNames='stateInLyr', ...
    ActionInputNames='actionInLyr');
critic = [critic1 critic2];

액터와 크리틱에 대한 훈련 옵션을 지정합니다.

actorOpts = rlOptimizerOptions( ...
    LearnRate=1e-3, ...
    GradientThreshold=1);

criticOpts = rlOptimizerOptions( ...
    LearnRate=1e-3, ...
    GradientThreshold=1);

rlTD3AgentOptions 객체를 사용하여 TD3 에이전트 옵션을 지정합니다. 액터와 크리틱에 대한 훈련 옵션을 포함시킵니다.

  • 제어기 샘플 시간 Ts를 사용하도록 에이전트를 설정합니다.

  • 미니 배치 크기를 128개의 경험 샘플로 설정합니다.

  • 경험 버퍼 길이를 1e6으로 설정합니다.

  • 탐색 모델과 타깃 정책 평활화 모델에서 분산 0.1의 가우스 잡음을 사용하도록 설정합니다.

agentOpts = rlTD3AgentOptions(...
    SampleTime=Ts,...
    MiniBatchSize=128, ...
    ExperienceBufferLength=1e6,...
    ActorOptimizerOptions=actorOpts,...
    CriticOptimizerOptions=criticOpts);

점 표기법을 사용하여 에이전트 옵션을 설정하거나 수정할 수도 있습니다.

agentOpts.TargetPolicySmoothModel.StandardDeviation = sqrt(0.1);

지정된 액터 표현, 크리틱 표현, 에이전트 옵션을 사용하여 TD3 에이전트를 만듭니다. 자세한 내용은 rlTD3AgentOptions 항목을 참조하십시오.

agent = rlTD3Agent(actor,critic,agentOpts);

에이전트 훈련시키기

에이전트를 훈련시키려면 먼저 다음 훈련 옵션을 지정하십시오.

  • 최대 1000개의 에피소드에 대해 각 훈련을 실행하며, 각 에피소드마다 최대 100개의 시간 스텝이 지속됩니다.

  • 에피소드 관리자에서 훈련 진행 상황을 표시하고(Plots 옵션 설정) 명령줄 표시를 비활성화합니다(Verbose 옵션 설정).

  • 연속 100개의 에피소드 동안 에이전트가 받은 평균 누적 보상이 -355보다 크면 훈련을 중지합니다. 이 시점에서 에이전트는 탱크에 있는 물의 수위를 제어할 수 있습니다.

자세한 내용은 rlTrainingOptions 항목을 참조하십시오.

maxepisodes = 1000;
maxsteps = ceil(Tf/Ts);
trainOpts = rlTrainingOptions(...
    MaxEpisodes=maxepisodes, ...
    MaxStepsPerEpisode=maxsteps, ...
    ScoreAveragingWindowLength=100, ...
    Verbose=false, ...
    Plots="training-progress",...
    StopTrainingCriteria="AverageReward",...
    StopTrainingValue=-355);

train 함수를 사용하여 에이전트를 훈련시킵니다. 이 에이전트를 훈련시키는 것은 완료하는 데 수 분이 소요되는 계산 집약적인 절차입니다. 이 예제를 실행하는 동안 시간을 절약하려면 doTrainingfalse로 설정하여 사전 훈련된 에이전트를 불러오십시오. 에이전트를 직접 훈련시키려면 doTrainingtrue로 설정하십시오.

doTraining = false;

if doTraining
    % Train the agent.
    trainingStats = train(agent,env,trainOpts);
else
    % Load pretrained agent for the example.
    load("WaterTankPIDtd3.mat","agent")
end

훈련된 에이전트 검증하기

모델에 대해 훈련된 에이전트를 시뮬레이션으로 검증합니다.

simOpts = rlSimulationOptions(MaxSteps=maxsteps);
experiences = sim(env,agent,simOpts);

PI 제어기의 적분 이득과 비례 이득은 액터 표현의 절대 가중치입니다. 이 가중치를 구하려면 먼저 액터에서 학습 가능한 파라미터를 추출합니다.

actor = getActor(agent);
parameters = getLearnableParameters(actor);

제어기 이득을 구합니다.

Ki = abs(parameters{1}(1))
Ki = single
    0.3958
Kp = abs(parameters{1}(2))
Kp = single
    8.0822

RL 에이전트로부터 구한 이득을 원래 PI Controller 블록에 적용하고 계단-응답 시뮬레이션을 실행합니다.

mdlTest = 'watertankLQG';
open_system(mdlTest); 
set_param([mdlTest '/PID Controller'],'P',num2str(Kp))
set_param([mdlTest '/PID Controller'],'I',num2str(Ki))
sim(mdlTest)

시뮬레이션의 계단 응답 정보, LQG 비용, 안정성 여유를 추출합니다. 안정성 여유를 계산하려면 이 예제 끝에 정의된 localStabilityAnalysis 함수를 사용합니다.

rlStep = simout;
rlCost = cost;
rlStabilityMargin = localStabilityAnalysis(mdlTest);

구해진 이득을 제어 시스템 조정기를 사용하여 원래 PI Controller 블록에 적용하고 계단-응답 시뮬레이션을 실행합니다.

set_param([mdlTest '/PID Controller'],'P',num2str(Kp_CST))
set_param([mdlTest '/PID Controller'],'I',num2str(Ki_CST))
sim(mdlTest)
cstStep = simout;
cstCost = cost;
cstStabilityMargin = localStabilityAnalysis(mdlTest);

제어기 성능 비교하기

각 시스템의 계단 응답을 플로팅합니다.

figure
plot(cstStep)
hold on
plot(rlStep)
grid on
legend('Control System Tuner','RL',Location="southeast")
title('Step Response')

Figure contains an axes object. The axes object with title Step Response, xlabel Time (seconds), ylabel y contains 2 objects of type line. These objects represent Control System Tuner, RL.

두 시뮬레이션의 계단 응답을 분석합니다.

rlStepInfo = stepinfo(rlStep.Data,rlStep.Time);
cstStepInfo = stepinfo(cstStep.Data,cstStep.Time);
stepInfoTable = struct2table([cstStepInfo rlStepInfo]);
stepInfoTable = removevars(stepInfoTable,{'SettlingMin', ...
    'TransientTime','SettlingMax','Undershoot','PeakTime'});
stepInfoTable.Properties.RowNames = {'CST','RL'};
stepInfoTable
stepInfoTable=2×4 table
           RiseTime    SettlingTime    Overshoot     Peak 
           ________    ____________    _________    ______

    CST    0.77737        1.3278        0.33125     9.9023
    RL     0.98024        1.7073        0.40451     10.077

두 시뮬레이션의 안정성을 분석합니다.

stabilityMarginTable = struct2table( ...
    [cstStabilityMargin rlStabilityMargin]);
stabilityMarginTable = removevars(stabilityMarginTable,{...
    'GMFrequency','PMFrequency','DelayMargin','DMFrequency'});
stabilityMarginTable.Properties.RowNames = {'CST','RL'};
stabilityMarginTable
stabilityMarginTable=2×3 table
           GainMargin    PhaseMargin    Stable
           __________    ___________    ______

    CST      8.1616        84.124       true  
    RL       9.9226        84.241       true  

두 제어기의 누적 LQG 비용을 비교합니다. RL 조정 제어기가 조금 더 나은 최적해를 생성합니다.

rlCumulativeCost  = sum(rlCost.Data)
rlCumulativeCost = -375.9135
cstCumulativeCost = sum(cstCost.Data)
cstCumulativeCost = -376.9373

두 제어기 모두 안정된 응답을 생성하며, 응답 속도는 제어 시스템 조정기를 사용하여 조정된 제어기가 더 빠릅니다. 하지만 RL 조정 방법이 더 높은 이득 여유와 더 나은 최적해를 생성합니다.

로컬 함수

물 탱크 RL 환경을 만드는 함수입니다.

function [env,obsInfo,actInfo] = localCreatePIDEnv(mdl)

% Define the observation specification obsInfo 
% and the action specification actInfo.
obsInfo = rlNumericSpec([2 1]);
obsInfo.Name = 'observations';
obsInfo.Description = 'integrated error and error';

actInfo = rlNumericSpec([1 1]);
actInfo.Name = 'PID output';

% Build the environment interface object.
env = rlSimulinkEnv(mdl,[mdl '/RL Agent'],obsInfo,actInfo);

% Set a cutom reset function that randomizes 
% the reference values for the model.
env.ResetFcn = @(in)localResetFcn(in,mdl);
end

각 에피소드가 시작할 때 탱크 내부의 초기 물 높이와 기준 신호를 무작위로 할당하는 함수입니다.

function in = localResetFcn(in,mdl)

% Randomize reference signal
blk = sprintf([mdl '/Desired \nWater Level']);
hRef = 10 + 4*(rand-0.5);
in = setBlockParameter(in,blk,'Value',num2str(hRef));

% Randomize initial water height
hInit = rand;
blk = [mdl '/Water-Tank System/H'];
in = setBlockParameter(in,blk,'InitialCondition',num2str(hInit));

end

SISO 물 탱크 시스템의 안정성 여유를 선형화하고 계산하는 함수입니다.

function margin = localStabilityAnalysis(mdl)

io(1) = linio([mdl '/Sum1'],1,'input');
io(2) = linio([mdl '/Water-Tank System'],1,'openoutput');
op = operpoint(mdl);
op.Time = 5;
linsys = linearize(mdl,io,op);

margin = allmargin(linsys);
end

크리틱 신경망을 만드는 함수입니다.

function criticNet = localCreateCriticNetwork(numObs,numAct)
statePath = [
    featureInputLayer(numObs,Name='stateInLyr')
    fullyConnectedLayer(32,Name='fc1')
    ];

actionPath = [
    featureInputLayer(numAct,Name='actionInLyr')
    fullyConnectedLayer(32,Name='fc2')
    ];

commonPath = [
    concatenationLayer(1,2,Name='concat')
    reluLayer
    fullyConnectedLayer(32)
    reluLayer
    fullyConnectedLayer(1,Name='qvalOutLyr')
    ];

criticNet = layerGraph();
criticNet = addLayers(criticNet,statePath);
criticNet = addLayers(criticNet,actionPath);
criticNet = addLayers(criticNet,commonPath);

criticNet = connectLayers(criticNet,'fc1','concat/in1');
criticNet = connectLayers(criticNet,'fc2','concat/in2');
end

참고 항목

함수

객체

관련 예제

세부 정보