exponenta event banner

Планирование системы распределения воды с использованием обучения усилению

В этом примере показано, как изучить оптимальную политику планирования насосов для системы распределения воды с использованием обучения армированию (RL).

Система распределения воды

На следующем рисунке показана система распределения воды.

Здесь:

  • QSsupply - количество воды, подаваемой в резервуар для воды из резервуара.

  • QDemand - это количество воды, вытекающей из резервуара для удовлетворения потребностей в использовании.

Целью средства обучения армированию является планирование количества работающих насосов для минимизации потребления энергии системой и удовлетворения потребности в использовании (h > 0). Дибамики танковой системы регулируются следующим уравнением.

Adhdt = QSsupply (t) -QDemand (t)

Здесь A = 40 м2 и hmax = 7m. Потребность в течение 24-часового периода является функцией времени, указанного как

QDemand (t) = (t) + (t)

где λ (t) является ожидаемой потребностью, а start( t) представляет неопределенность потребности, которая выбирается из равномерного случайного распределения.

Подача определяется количеством работающих насосов в a∈{0,1,2,3}according со следующим отображением.

QSuply (t) = Q (a) = {0a = 0164a = 1279a = 2344a = 3 cmh

Для упрощения проблемы энергопотребление определяется как количество работающих насосов, а.

Следующая функция является наградой для этой среды. Во избежание переполнения или опорожнения резервуара добавляются дополнительные расходы, если высота воды близка к максимальному или минимальному уровню воды, hmaxor hmin, соответственно.

r (h, a) = -10 (h≥ (hmax-0,1)) -10 (h≤0.1) -a

Создать профиль спроса

Чтобы создать и профиль потребности в воде на основе количества рассмотренных дней, используйте generateWaterDemand функция, определенная в конце этого примера.

num_days = 4; % Number of days
[WaterDemand,T_max] = generateWaterDemand(num_days);

Просмотр профиля спроса.

plot(WaterDemand)

Figure contains an axes. The axes with title Time Series Plot:Water Demand contains an object of type line.

Открытие и настройка модели

Откройте распределительную систему Simulink model.

mdl = "watertankscheduling";
open_system(mdl)

В дополнение к агенту обучения усилению в блоке функции MATLAB закона управления определен простой контроллер базовой линии. Этот контроллер включает определенное количество насосов в зависимости от уровня воды.

Укажите начальную высоту воды.

h0 = 3; % m

Укажите параметры модели.

SampleTime = 0.2;
H_max = 7; % Max tank height (m)
A_tank = 40; % Area of tank (m^2)

Создание интерфейса среды для агента RL

Чтобы создать интерфейс среды для модели 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

Агент 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);

Создание агента DQN

Чтобы создать агента, сначала укажите его параметры. При использовании сети 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);    

Агент поезда

Для обучения агента сначала укажите варианты обучения. В этом примере используются следующие опции.

  • Запустить обучение для 1000 серий, с каждым эпизодом длительностью в ceil(T_max/Ts) временные шаги.

  • Отображение хода обучения в диалоговом окне «Менеджер эпизодов» (установите 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

На следующем рисунке показан ход обучения.

Моделирование агента DQN

Для проверки работоспособности обучаемого агента смоделируйте его в среде водоемов. Дополнительные сведения о моделировании агентов см. в разделе rlSimulationOptions и sim.

Для моделирования производительности агента подключите блок агента RL путем переключения блока ручного переключения.

set_param(mdl+"/Manual Switch",'sw','0');

Установите максимальное количество шагов для каждого моделирования и количество моделирований. В этом примере выполните 30 моделирований. Функция сброса среды устанавливает различную начальную высоту воды, и потребность в воде различна в каждом моделировании.

NumSimulations = 30;
simOptions = rlSimulationOptions('MaxSteps',T_max/SampleTime,...
    'NumSimulations', NumSimulations);

Для сравнения агента с контроллером базовой линии при тех же условиях сбросьте начальное случайное начальное число, используемое в функции сброса среды.

env.ResetFcn("Reset seed");

Смоделировать агент против окружающей среды.

experienceDQN = sim(env,agent,simOptions);

Моделирование контроллера базовой линии

Для сравнения агента DQN с контроллером базовой линии необходимо смоделировать контроллер базовой линии, используя те же опции моделирования и начальное случайное начальное значение для функции сброса.

Включите базовый контроллер.

set_param(mdl+"/Manual Switch",'sw','1');

Для сравнения агента с контроллером базовой линии при тех же условиях сбросьте случайное начальное значение, используемое в функции сброса среды.

env.ResetFcn("Reset seed");

Смоделировать базовый контроллер в зависимости от среды.

experienceBaseline = sim(env,agent,simOptions);

Сравнение агента DQN с базовым контроллером

Инициализируйте векторы совокупного результата вознаграждения как для агента, так и для базового контроллера.

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')

Figure contains an axes. The axes contains 2 objects of type line. These objects represent DQN, Baseline.

Совокупное вознаграждение, полученное агентом, постоянно составляет около -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