基于强化学习的配水系统调度
这个例子展示了如何使用强化学习(RL)学习水分配系统的最优泵调度策略。
配水系统
下图为给水系统。
在这里:
是指从水库向水箱提供的水量。
是指从水箱中流出的水量满足使用需求。
强化学习剂的目标是调度运行的泵的数量,使系统的能源消耗最小化,并满足使用需求( ).坦克系统的动力学由下式决定。
在这里, 而且 .24小时内的需求是给定时间的函数
在哪里 是预期需求和 表示需求的不确定性,它是从均匀随机分布中采样的。
供水量由运行的泵的数量决定, 根据下面的映射。
为了简化问题,功耗被定义为运行泵的数量, .
下面的功能是对这个环境的奖励。为了避免水箱溢出或排空,如果水的高度接近最高或最低水位,就要增加额外的费用。 或 ,分别。
生成需求概要
要根据考虑的天数生成水需求概况,请使用generateWaterDemand
在本例末尾定义的函数。
num_days = 4;%天数[WaterDemand, T_max] = generateWaterDemand (num_days);
查看需求配置文件。
情节(WaterDemand)
打开并配置模型
打开配电系统Simulink模型。
mdl =“watertankscheduling”;open_system (mdl)
除了强化学习代理,在控制律MATLAB函数块中定义了一个简单的基线控制器。这个控制器根据水位启动一定数量的泵。
指定初始水高。
h0 = 3;% m
指定模型参数。
SampleTime = 0.2;H_max = 7;最大储罐高度(m)A_tank = 40;槽面积% (m^2)
为RL代理创建环境接口
要为Simulink模型创建一个环境接口,首先要定义动作和观察规范,actInfo
而且obsInfo
,分别。代理动作是选择的泵的数量。代理观测是水的高度,它是作为连续时间信号测量的。
actInfo = rlFiniteSetSpec ([0, 1, 2, 3]);obsInfo = rlNumericSpec ([1]);
创建环境接口。
env = rlSimulinkEnv (mdl mdl +“/ RL代理”、obsInfo actInfo);
指定一个自定义重置函数,该函数在本例的最后定义,它随机设置初始水高和需水量。这样做可以让代理对不同的初始水位和每个章节的水需求函数进行训练。
env。ResetFcn = @(在)localResetFcn(的);
创建DQN代理
DQN代理在给定的观察和行动下,使用临界q -值函数表示逼近长期奖励。要创建评论家,首先要创建一个深度神经网络。有关创建深度神经网络值函数表示的更多信息,请参见创建政策和价值功能.
修复随机生成器种子的可重复性。rng (0);
为评论家建立一个深度神经网络。对于本例,使用非循环神经网络。要使用循环神经网络,设置useLSTM
来真正的
.
useLSTM = false;如果useLSTM layers = [sequenceInputLayer(obsInfo.Dimension(1),“名称”,“状态”,“归一化”,“没有”) fullyConnectedLayer (32,“名称”,“fc_1”) reluLayer (“名称”,“relu_body1”) lstmLayer (32,“名称”,“lstm”) fullyConnectedLayer (32,“名称”,“fc_3”) reluLayer (“名称”,“relu_body3”) fullyConnectedLayer(元素个数(actInfo.Elements),“名称”,“输出”));其他的layers = [featureInputLayer(obsInfo.Dimension(1),“名称”,“状态”,“归一化”,“没有”) fullyConnectedLayer (32,“名称”,“fc_1”) reluLayer (“名称”,“relu_body1”) fullyConnectedLayer (32,“名称”,“fc_2”) reluLayer (“名称”,“relu_body2”) fullyConnectedLayer (32,“名称”,“fc_3”) reluLayer (“名称”,“relu_body3”) fullyConnectedLayer(元素个数(actInfo.Elements),“名称”,“输出”));结束款= dlnetwork(层);
指定用于创建批评家表示的选项。
criticOpts = rlOptimizerOptions (“LearnRate”, 0.001,“GradientThreshold”1);
使用带有定义的深度神经网络和选项的rlVectorQValueFunction创建一个批评家。
评论家= rlVectorQValueFunction(款、obsInfo actInfo);
创建DQN代理
要创建代理,首先指定代理选项。如果使用LSTM网络,则将序列长度设置为20.
.
选择= rlDQNAgentOptions (“SampleTime”, SampleTime);如果useLSTM opt.SequenceLength = 20;其他的opt.SequenceLength = 1;结束opt.DiscountFactor = 0.995;opt.ExperienceBufferLength = 1 e6;opt.EpsilonGreedyExploration.EpsilonDecay = 1 e-5;opt.EpsilonGreedyExploration.EpsilonMin = .02点;opt.CriticOptimizerOptions = criticOpts;
使用定义的选项和批评家表示创建代理。
代理= rlDQNAgent(评论家,选择);
火车代理
要培训代理,首先要指定培训选项。对于本例,使用以下选项。
跑步训练1000集,每集持续在
装天花板(T_max / Ts)
时间的步骤。在“集训管理器”对话框中显示训练进度
情节
选项)
类指定培训选项rlTrainingOptions
对象。
trainOpts = rlTrainingOptions (...“MaxEpisodes”, 1000,...“MaxStepsPerEpisode”装天花板(T_max / SampleTime),...“详细”假的,...“阴谋”,“训练进步”,...“StopTrainingCriteria”,“EpisodeCount”,...“StopTrainingValue”, 1000,...“ScoreAveragingWindowLength”, 100);
虽然在本例中不这样做,但是可以在训练过程中保存代理。例如,以下选项保存奖励值大于或等于的每个代理-42年
.
如果需要,使用SaveAgentCriteria保存代理。SaveAgentCriteria =“EpisodeReward”;trainOpts。SaveAgentValue = -42;
训练代理使用火车
函数。训练这个代理是一个计算密集的过程,需要几个小时才能完成。要在运行此示例时节省时间,请通过设置加载预先训练过的代理doTraining
来假
.亲自训练探员,设doTraining
来真正的
.
doTraining = false;如果doTraining培训代理。通过拨动手动开关块连接RL Agent块set_param (mdl +“/手动开关”,“西南”,' 0 ');trainingStats =火车(代理,env, trainOpts);其他的为示例加载预先训练过的代理。负载(“SimulinkWaterDistributionDQN.mat”,“代理”)结束
训练进度如下图所示。
模拟DQN代理
为了验证训练过的代理的性能,在水箱环境中进行了模拟。有关代理模拟的更多信息,请参见rlSimulationOptions
而且sim卡
.
为了模拟代理的性能,可以通过手动开关块连接RL agent块。
set_param (mdl +“/手动开关”,“西南”,' 0 ');
设置每个模拟的最大步骤数和模拟次数。对于本例,运行30个模拟。环境重置功能设置不同的初始水高,每次模拟的需水量不同。
NumSimulations = 30;simOptions = rlSimulationOptions (“MaxSteps”T_max / SampleTime...“NumSimulations”, NumSimulations);
为了将代理与相同条件下的基线控制器进行比较,重置环境重置函数中使用的初始随机种子。
env。ResetFcn (“重置种子”);
根据环境模拟代理。
experienceDQN = sim (env,代理,simOptions);
模拟基线控制器
要比较DQN代理与基线控制器,必须使用相同的模拟选项和重置函数的初始随机种子来模拟基线控制器。
启用基线控制器。
set_param (mdl +“/手动开关”,“西南”,' 1 ');
为了将代理与相同条件下的基线控制器进行比较,重置环境重置函数中使用的随机种子。
env。ResetFcn (“重置种子”);
根据环境模拟基线控制器。
experienceBaseline = sim (env,代理,simOptions);
比较DQN代理和基线控制器
初始化代理和基线控制器的累积奖励结果向量。
resultectordqn = 0 (numsimulation, 1);resultVectorBaseline = 0 (NumSimulations, 1);
计算代理和基线控制器的累积奖励。
为ct = 1: numsimulation resultectordqn (ct) = sum(experienceDQN(ct).Reward);resultVectorBaseline (ct) =总和(experienceBaseline (ct) .Reward);结束
绘制累积奖励。
情节([resultVectorDQN resultVectorBaseline),“o”甘氨胆酸)组(,“xtick”1: NumSimulations)包含(“模拟数字”) ylabel (“累积奖励”)传说(“DQN”,“基线”,“位置”,“NorthEastOutside”)
代理获得的累积奖励始终在-40左右。这个值远远大于基线控制器获得的平均奖励。因此,DQN代理在节能方面始终优于基线控制器。
本地函数
水需求函数
函数[WaterDemand,T_max] = generateWaterDemand(num_days) t = 0:(num_days*24)-1;%的人力资源T_max = t(结束);Demand_mean = [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 /人力资源需求= repmat (Demand_mean 1 num_days);需求=需求(:);为需求增加噪音一个= -25;% m ^ 3 /人力资源b = 25;% m ^ 3 /人力资源Demand_noise = a + (b-a).*rand(numel(Demand),1);水需求=时间序列(需求+需求噪声,t);WaterDemand。Name =“水需求”;WaterDemand.TimeInfo.Units =“小时”;结束
重置功能
函数= localResetFcn(中)使用持久的随机种子值来评估代理和基线%控制器在相同条件下。持续的randomSeed如果isempty(randomSeed) randomSeed = 0;结束如果比较字符串(在“重置种子”) randomSeed = 0;返回结束randomSeed = randomSeed + 1;rng (randomSeed)随机分配需水量。num_days = 4;H_max = 7;[WaterDemand ~] = generateWaterDemand (num_days);assignin (“基地”,“WaterDemand”WaterDemand)随机初始高度。h0 = 3 * randn;而h0 <= 0 || h0 >= H_max h0 = 3*randn;结束黑色=“水箱调度/水箱系统/初始水位”;在= setBlockParameter(黑色,“价值”num2str (h0));结束