В этом примере показано, как изучить оптимальную политику планирования насоса для водной системы распределения с помощью обучения с подкреплением (RL).
Следующий рисунок показывает водную систему распределения.
Здесь:
количество воды, предоставленной баку с водой от резервуара.
количество воды, вытекающей из бака, чтобы удовлетворить спросу на использование.
Цель агента обучения с подкреплением состоит в том, чтобы запланировать количество насосов, запускающихся, чтобы и минимизировать энергетическое использование системы и удовлетворить спросу на использование (). Движущими силами системы бака управляет следующее уравнение.
Здесь, и . Спрос за 24-часовой период является функцией времени, данного как
где ожидаемый спрос и представляет неопределенность спроса, которая производится от универсального случайного распределения.
Предоставление определяется количеством выполнения насосов, согласно следующему отображению.
Чтобы упростить проблему, потребление энергии задано как количество выполнения насосов, .
Следующая функция является вознаграждением за эту среду. Чтобы постараться не переполнять или опорожнять бак, дополнительная стоимость добавляется, если уровень воды близко к максимальному или минимальному уровню воды, или , соответственно.
Чтобы сгенерировать и профиль водопотребности на основе номера рассмотренных дней, используйте generateWaterDemand
функция, определяемая в конце этого примера.
num_days = 4; % Number of days
[WaterDemand,T_max] = generateWaterDemand(num_days);
Просмотрите профиль спроса.
plot(WaterDemand)
Откройте модель Simulink системы распределения.
mdl = "watertankscheduling";
open_system(mdl)
В дополнение к агенту обучения с подкреплением простой базовый контроллер задан в блоке MATLAB function Закона о надзоре. Этот диспетчер активирует определенное число насосов в зависимости от уровня воды.
Задайте начальный уровень воды.
h0 = 3; % m
Задайте параметры модели.
SampleTime = 0.2; H_max = 7; % Max tank height (m) A_tank = 40; % Area of tank (m^2)
Чтобы создать интерфейс среды для модели Simulink, сначала задайте действие и спецификации наблюдений, actInfo
и obsInfo
, соответственно. Действие агента является выбранным количеством насосов. Наблюдение агента является уровнем воды, который измеряется как сигнал непрерывного времени.
actInfo = rlFiniteSetSpec([0,1,2,3]); obsInfo = rlNumericSpec([1,1]);
Создайте интерфейс среды.
env = rlSimulinkEnv(mdl,mdl+"/RL Agent",obsInfo,actInfo);
Задайте пользовательскую функцию сброса, которая задана в конце этого примера, который рандомизирует начальный уровень воды и водопотребность. Выполнение так позволяет агенту быть обученным на различном начальном уровне воды и функциях водопотребности для каждого эпизода.
env.ResetFcn = @(in)localResetFcn(in);
Агент DQN аппроксимирует долгосрочное вознаграждение, заданные наблюдения и действия, с помощью представления Q-функции-ценности критика. Чтобы создать критика, сначала создайте глубокую нейронную сеть. Для получения дополнительной информации о создании представления функции ценности глубокой нейронной сети смотрите, Создают Представления Функции ценности и политика.
% Fix the random generator seed for reproducibility.
rng(0);
Создайте глубокую нейронную сеть для критика. В данном примере используйте единовременную нейронную сеть. Чтобы использовать рекуррентную нейронную сеть, установите useLSTM
к true
.
useLSTM = false; if useLSTM layers = [ sequenceInputLayer(obsInfo.Dimension(1),"Name","state","Normalization","none") fullyConnectedLayer(32,"Name","fc_1") reluLayer("Name","relu_body1") lstmLayer(32,"Name","lstm") fullyConnectedLayer(32,"Name","fc_3") reluLayer("Name","relu_body3") fullyConnectedLayer(numel(actInfo.Elements),"Name","output")]; else layers = [ featureInputLayer(obsInfo.Dimension(1),"Name","state","Normalization","none") fullyConnectedLayer(32,"Name","fc_1") reluLayer("Name","relu_body1") fullyConnectedLayer(32,"Name","fc_2") reluLayer("Name","relu_body2") fullyConnectedLayer(32,"Name","fc_3") reluLayer("Name","relu_body3") fullyConnectedLayer(numel(actInfo.Elements),"Name","output")]; end
Задайте опции для создания представления критика.
criticOpts = rlRepresentationOptions('LearnRate',0.001,'GradientThreshold',1);
Создайте представление критика с помощью заданной глубокой нейронной сети и опций.
critic = rlQValueRepresentation(layerGraph(layers),obsInfo,actInfo,... 'Observation',{'state'},criticOpts);
Чтобы создать агента, сначала задайте опции агента. Если вы используете сеть LSTM, установите длину последовательности на 20
.
opt = rlDQNAgentOptions('SampleTime',SampleTime); if useLSTM opt.SequenceLength = 20; else opt.SequenceLength = 1; end opt.DiscountFactor = 0.995; opt.ExperienceBufferLength = 1e6; opt.EpsilonGreedyExploration.EpsilonDecay = 1e-5; opt.EpsilonGreedyExploration.EpsilonMin = .02;
Создайте агента с помощью заданных опций и представления критика.
agent = rlDQNAgent(critic,opt);
Чтобы обучить агента, сначала задайте опции обучения. В данном примере используйте следующие опции.
Запустите обучение 1 000 эпизодов с каждым эпизодом, длящимся в ceil(T_max/Ts)
временные шаги.
Отобразите прогресс обучения в диалоговом окне Episode Manager (установите Plots
опция)
Задайте опции для обучения с помощью rlTrainingOptions
объект.
trainOpts = rlTrainingOptions(... 'MaxEpisodes',1000, ... 'MaxStepsPerEpisode',ceil(T_max/SampleTime), ... 'Verbose',false, ... 'Plots','training-progress',... 'StopTrainingCriteria','EpisodeCount',... 'StopTrainingValue',1000,... 'ScoreAveragingWindowLength',100);
В то время как вы не делаете этого для этого примера, можно сохранить агентов во время учебного процесса. Например, следующие опции сохраняют каждого агента с премиальным значением, больше, чем или равный -42
.
Save agents using SaveAgentCriteria if necessary trainOpts.SaveAgentCriteria = 'EpisodeReward'; trainOpts.SaveAgentValue = -42;
Обучите агента с помощью train
функция. Обучение этот агент является в вычислительном отношении интенсивным процессом, который занимает несколько часов, чтобы завершиться. Чтобы сэкономить время при выполнении этого примера, загрузите предварительно обученного агента установкой doTraining
к false
. Чтобы обучить агента самостоятельно, установите doTraining
к true
.
doTraining = false; if doTraining % Train the agent. trainingStats = train(agent,env,trainOpts); else % Load the pretrained agent for the example. load('SimulinkWaterDistributionDQN.mat','agent') end
Следующий рисунок показывает процесс обучения.
Чтобы подтвердить производительность обученного агента, симулируйте его в среде бака с водой. Для получения дополнительной информации о симуляции агента смотрите rlSimulationOptions
и sim
.
Чтобы симулировать эффективность агента, соедините блок RL Agent путем переключения ручного блока switch.
set_param(mdl+"/Manual Switch",'sw','0');
Определите максимальный номер шагов для каждой симуляции и количества симуляций. В данном примере запустите 30 симуляций. Функция сброса среды устанавливает различный начальный уровень воды, и водопотребность отличаются в каждой симуляции.
NumSimulations = 30; simOptions = rlSimulationOptions('MaxSteps',T_max/SampleTime,... 'NumSimulations', NumSimulations);
Чтобы сравнить агента с базовым контроллером при тех же условиях, сбросьте начальный случайный seed, используемый в функции сброса среды.
env.ResetFcn("Reset seed");
Симулируйте агента против среды.
experienceDQN = sim(env,agent,simOptions);
Чтобы сравнить агента DQN с базовым контроллером, необходимо симулировать базовый контроллер, использующий те же опции симуляции и начальный случайный seed для функции сброса.
Включите базовому контроллеру.
set_param(mdl+"/Manual Switch",'sw','1');
Чтобы сравнить агента с базовым контроллером при тех же условиях, сбросьте случайный seed, используемый в функции сброса среды.
env.ResetFcn("Reset seed");
Симулируйте базовый контроллер против среды.
experienceBaseline = sim(env,agent,simOptions);
Инициализируйте совокупные премиальные итоговые векторы и для агента и для базового контроллера.
resultVectorDQN = zeros(NumSimulations, 1); resultVectorBaseline = zeros(NumSimulations,1);
Вычислите совокупные вознаграждения и за агента и за базовый контроллер.
for ct = 1:NumSimulations resultVectorDQN(ct) = sum(experienceDQN(ct).Reward); resultVectorBaseline(ct) = sum(experienceBaseline(ct).Reward); end
Постройте совокупные вознаграждения.
plot([resultVectorDQN resultVectorBaseline],'o') set(gca,'xtick',1:NumSimulations) xlabel("Simulation number") ylabel('Cumulative Reward') legend('DQN','Baseline','Location','NorthEastOutside')
Совокупное вознаграждение, полученное агентом, последовательно является приблизительно-40. Это значение очень больше среднего вознаграждения, полученного базовым контроллером. Поэтому агент DQN последовательно превосходит базовый контроллер по характеристикам в терминах энергосбережений.
Функция водопотребности
function [WaterDemand,T_max] = generateWaterDemand(num_days) t = 0:(num_days*24)-1; % hr T_max = t(end); Demand_mean = [28, 28, 28, 45, 55, 110, 280, 450, 310, 170, 160, 145, 130, ... 150, 165, 155, 170, 265, 360, 240, 120, 83, 45, 28]'; % m^3/hr Demand = repmat(Demand_mean,1,num_days); Demand = Demand(:); % Add noise to demand a = -25; % m^3/hr b = 25; % m^3/hr Demand_noise = a + (b-a).*rand(numel(Demand),1); WaterDemand = timeseries(Demand + Demand_noise,t); WaterDemand.Name = "Water Demand"; end
Функция сброса
function in = localResetFcn(in) % Use a persistent random seed value to evaluate the agent and the baseline % controller under the same conditions. persistent randomSeed if isempty(randomSeed) randomSeed = 0; end if strcmp(in,"Reset seed") randomSeed = 0; return end randomSeed = randomSeed + 1; rng(randomSeed) % Randomize water demand. num_days = 4; H_max = 7; [WaterDemand,~] = generateWaterDemand(num_days); assignin('base','WaterDemand',WaterDemand) % Randomize initial height. h0 = 3*randn; while h0 <= 0 || h0 >= H_max h0 = 3*randn; end blk = 'watertankscheduling/Water Tank System/Initial Water Height'; in = setBlockParameter(in,blk,'Value',num2str(h0)); end