이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.
강화 학습을 사용하여 PI 제어기 조정하기
이 예제에서는 TD3(Twin-Delayed Deep Deterministic: 트윈 지연 심층 결정적) 정책 경사법 강화 학습 알고리즘을 사용하여 PI 제어기를 조정하는 방법을 보여줍니다. 조정된 제어기의 성능은 제어 시스템 조정기 앱을 사용하여 조정된 제어기의 성능과 비교됩니다. Simulink®에서 제어 시스템 조정기 앱을 사용하여 제어기를 조정하려면 Simulink Control Design™이 필요합니다.
조정 가능형 파라미터 수가 적어 비교적 간단한 제어 작업의 경우 모델 기반 조정 기법을 사용하면 모델이 주어지지 않은(model-free) RL 기반 방법보다 조정 처리가 더 빠르며 좋은 결과를 얻을 수 있습니다. 하지만 상당히 비선형적인 시스템이나 적응형 제어기 조정 작업에는 RL 방법이 더 적절할 수 있습니다.
제어기 비교가 용이하도록 두 조정 방법에는 선형 2차 가우스(LQG) 목적 함수가 사용됩니다.
이 예제에서는 강화 학습(RL) 에이전트를 사용하여 PI 제어기에 대한 이득을 계산합니다. PI 제어기를 신경망 제어기로 바꾸는 예제는 Simulink 환경 만들기 및 에이전트 훈련시키기 항목을 참조하십시오.
환경 모델
이 예제의 환경 모델은 물탱크 모델입니다. 이 제어 시스템의 목표는 탱크에 있는 물의 수위를 기준 값과 일치하도록 유지하는 것입니다.
open_system('watertankLQG')
모델에는 분산 을 갖는 공정 잡음이 포함되어 있습니다.
물의 수위를 유지하면서도 제어 노력 u
를 최소화하기 위해 이 예제의 제어기에는 다음 LQG 기준이 사용됩니다.
이 모델에서 제어기를 시뮬레이션하기 위해, 시뮬레이션 시간 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 에이전트 훈련을 위한 모델을 정의하려면 다음 단계에 따라 물 탱크 모델을 수정하십시오.
PID 제어기를 삭제합니다.
RL Agent 블록을 삽입합니다.
관측값 벡터 를 만듭니다. 여기서 이고, 는 탱크의 높이이며, 는 기준 높이입니다. RL Agent 블록에 관측값 신호를 연결합니다.
RL 에이전트의 보상 함수를 LQG 비용의 음수로 정의합니다. 즉, 입니다. RL 에이전트는 이 보상을 최대화하므로 LQG 비용을 최소화합니다.
결과로 생성되는 모델은 rlwatertankPIDTune.slx
입니다.
mdl = 'rlwatertankPIDTune';
open_system(mdl)
환경 인터페이스 객체를 만듭니다. 이를 위해, 이 예제 끝에 정의된 localCreatePIDEnv
함수를 사용합니다.
[env,obsInfo,actInfo] = localCreatePIDEnv(mdl);
이 환경에 대한 관측값 및 행동 차원을 추출합니다.
numObservations = obsInfo.Dimension(1); numActions = prod(actInfo.Dimension);
재현이 가능하도록 난수 생성기 시드값을 고정합니다.
rng(0)
TD3 에이전트 만들기
주어진 관측값에 대해, TD3 에이전트는 액터 표현을 사용하여 어떤 행동을 수행할지 결정합니다. 액터를 만들려면 먼저 관측값 입력값과 행동 출력값을 갖는 심층 신경망을 만드십시오. 자세한 내용은 rlContinuousDeterministicActor
항목을 참조하십시오.
PI 제어기를 하나의 완전 연결 계층을 가지며 오차와 오차 적분 관측값을 사용하는 신경망으로 모델링할 수 있습니다.
여기서 각 요소는 다음과 같습니다.
u
는 액터 신경망의 출력값입니다.Kp
와Ki
는 신경망 가중치의 절댓값입니다.이고, 는 탱크의 높이이며, 는 기준 높이입니다.
경사하강법 최적화에서는 가중치가 음수 값이 될 수 있습니다. 음수 가중치를 피하려면 표준 fullyConnectedLayer
를 fullyConnectedPILayer
로 바꾸십시오. 이 계층은 함수 를 구현하기 때문에 가중치가 양수가 되도록 합니다. 이 계층은 fullyConnectedPILayer.m
에 정의되어 있습니다. 사용자 지정 계층 정의에 대한 자세한 내용은 사용자 지정 딥러닝 계층 정의하기 항목을 참조하십시오.
initialGain = single([1e-3 2]); actorNetwork = [ featureInputLayer(numObservations,'Normalization','none','Name','state') fullyConnectedPILayer(initialGain, 'Action')]; actorNetwork = dlnetwork(actorNetwork); actorOptions = rlOptimizerOptions('LearnRate',1e-3,'GradientThreshold',1); actor = rlContinuousDeterministicActor(actorNetwork,obsInfo,actInfo);
TD3 에이전트는 관측값과 행동이 주어지면 2개의 크리틱 가치 함수 표현을 사용하여 장기 보상을 근사합니다. 크리틱을 만들려면 먼저 관측값과 행동에 해당하는 2개의 입력값 및 1개의 출력값을 갖는 심층 신경망을 만드십시오. 심층 신경망 가치 함수 표현을 만드는 방법에 대한 자세한 내용은 Create Policies and Value Functions 항목을 참조하십시오.
크리틱을 만들려면 이 예제 끝에 정의된 localCreateCriticNetwork
함수를 사용합니다. 두 크리틱 표현에 동일한 신경망 구조를 사용합니다.
criticNetwork = localCreateCriticNetwork(numObservations,numActions); criticOpts = rlOptimizerOptions('LearnRate',1e-3,'GradientThreshold',1); critic1 = rlQValueFunction(dlnetwork(criticNetwork),obsInfo,actInfo,... 'ObservationInputNames','state','ActionInputNames','action'); critic2 = rlQValueFunction(dlnetwork(criticNetwork),obsInfo,actInfo,... 'ObservationInputNames','state','ActionInputNames','action'); critic = [critic1 critic2];
다음 옵션을 사용하여 에이전트를 구성합니다.
제어기 샘플 시간
Ts
를 사용하도록 에이전트를 설정합니다.미니 배치 크기를 128개의 경험 샘플로 설정합니다.
경험 버퍼 길이를 1e6으로 설정합니다.
탐색 모델과 타깃 정책 평활화 모델에서 분산 0.1의 가우스 잡음을 사용하도록 설정합니다.
rlTD3AgentOptions
객체를 사용하여 TD3 에이전트 옵션을 지정합니다.
agentOpts = rlTD3AgentOptions(... 'SampleTime',Ts,... 'MiniBatchSize',128, ... 'ExperienceBufferLength',1e6,... 'ActorOptimizerOptions',actorOptions,... '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
함수를 사용하여 에이전트를 훈련시킵니다. 이 에이전트를 훈련시키는 것은 완료하는 데 수 분이 소요되는 계산 집약적인 절차입니다. 이 예제를 실행하는 동안 시간을 절약하려면 doTraining
을 false
로 설정하여 사전 훈련된 에이전트를 불러오십시오. 에이전트를 직접 훈련시키려면 doTraining
을 true
로 설정하십시오.
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')
두 시뮬레이션의 계단 응답을 분석합니다.
rlStepInfo = stepinfo(rlStep.Data,rlStep.Time); cstStepInfo = stepinfo(cstStep.Data,cstStep.Time); stepInfoTable = struct2table([cstStepInfo rlStepInfo]); stepInfoTable = removevars(stepInfoTable,{... 'SettlingMin','SettlingMax','Undershoot','PeakTime'}); stepInfoTable.Properties.RowNames = {'Control System Tuner','RL'}; stepInfoTable
stepInfoTable=2×5 table
RiseTime TransientTime SettlingTime Overshoot Peak
________ _____________ ____________ _________ ______
Control System Tuner 0.77737 1.3594 1.3278 0.33125 9.9023
RL 0.98024 1.7408 1.7073 0.40451 10.077
두 시뮬레이션의 안정성을 분석합니다.
stabilityMarginTable = struct2table([cstStabilityMargin rlStabilityMargin]); stabilityMarginTable = removevars(stabilityMarginTable,{... 'GMFrequency','PMFrequency','DelayMargin','DMFrequency'}); stabilityMarginTable.Properties.RowNames = {'Control System Tuner','RL'}; stabilityMarginTable
stabilityMarginTable=2×3 table
GainMargin PhaseMargin Stable
__________ ___________ ______
Control System Tuner 8.1616 84.124 true
RL 9.9226 84.242 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 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 height hInit = 0; 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 criticNetwork = localCreateCriticNetwork(numObservations,numActions) statePath = [ featureInputLayer(numObservations,'Normalization','none','Name','state') fullyConnectedLayer(32,'Name','fc1')]; actionPath = [ featureInputLayer(numActions,'Normalization','none','Name','action') fullyConnectedLayer(32,'Name','fc2')]; commonPath = [ concatenationLayer(1,2,'Name','concat') reluLayer('Name','reluBody1') fullyConnectedLayer(32,'Name','fcBody') reluLayer('Name','reluBody2') fullyConnectedLayer(1,'Name','qvalue')]; criticNetwork = layerGraph(); criticNetwork = addLayers(criticNetwork,statePath); criticNetwork = addLayers(criticNetwork,actionPath); criticNetwork = addLayers(criticNetwork,commonPath); criticNetwork = connectLayers(criticNetwork,'fc1','concat/in1'); criticNetwork = connectLayers(criticNetwork,'fc2','concat/in2'); end