精华内容
下载资源
问答
  • DQN最短路径MATLAB.zip

    2020-05-26 21:25:03
    不用强化学习工具箱的DQN算法案例与matlab代码,方便大家学习使用。可以在此基础上直接更改编写自己的项目
  • MATLAB临时间隔代码 自述文件作者:简建元隶属:Wireless,ECE,Virginia Tech 电子邮件 : 日期:2018年4月 目录 概述 该项目围绕在动态信道访问中应用深层Q网络[1]进行工作。 它可以验证智能节点访问信道的性能,...
  • MATLAB手动实现DQN最短路径问题

    千次阅读 热门讨论 2020-05-22 22:51:41
    不用强化学习工具箱的DQN算法案例与matlab代码 本文建立在已经有DQN基础知识之上。 案例说明: 环境设置:这是一个30*30的矩阵迷宫,其中有两个状态obstacle(15,15),Goal(25,25),目标就是Agent如何不碰到障碍物可以...

    完整代码链接,点击打开下载即可

    不用强化学习工具箱的DQN算法案例与matlab代码


    本文建立在已经有DQN基础知识之上。

    案例说明:

    环境设置:这是一个30*30的矩阵迷宫,其中有两个状态obstacle(15,15),Goal(25,25),目标就是Agent如何不碰到障碍物可以到达Goal.
    奖励设置:当Agent到达obstacle状态时reward=-1;当Agent到达Goal状态时reward=1;其他状态下reward=0.
    状态设置:所在方块中x,y为状态;
    动作设置:上,下,左,右。并且设置了随机性,当选动作上时,有80%概率选择上,10%概率选择左,10%概率选择右。
    通过不断的学习使得Agent能够选择最优路径。

    DQN与Q-learning区别

    1. 解决了状态空间太大问题;
    2. 利用神经网络逼近值函数代替Q-table,注意自己的数据是否一定要选择深度卷积网络,浅层网络能解决的就不用了深度神经网络了,本质就是神经网络逼近问题,本文用的最简单的神经网络BP去做的。
    3. 采用了经验回放,可以理解为我们用了一个容器去承载我们过去学习到经验,打破数据之间的关联。目前有一些文章研究了关于如何采样方面的方法,有需要的可以自行查阅,有时间会给大家分享我看到的文章。
      -------------话不多说我们上代码这里只提供一部分,全部的会上传到资源上)代码已上传,大家可以在此基础上直接修改变成自己的项目。
    function DQN
    close all;
    clear; clc;
    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    isTraining = true; %declare if it is training
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    
    addpath('../Environment');
    addpath('../Basic Functions');
    env = SAEnvironment;
    
    alpha = 0.1; %learning rate settings 
    gamma = 0.9; %discount factor
    maxItr = 3000;%maximum iterations for ending one episode
    
    hidden_layer = [40 40];
    estimator = DQNEstimator(env,alpha,hidden_layer);
    
    if isTraining
        %replay buffer
        memory_size = 30000;
        memory_cnt = 0;
        batch_size = 3000;
        memory_buffer(1:memory_size) = struct('state',[],'action',[],'next_state',[],'reward',[],'done',[]);
        
        
        NUM_ITERATIONS = 20000; %change this value to set max iterations
        epsilon = 0.8; %random action choice
        min_epsilon = 0.3;
        iterationCount(NUM_ITERATIONS) = 0;
        rwd(NUM_ITERATIONS) = 0;
    else
        NUM_ITERATIONS = 5;
        epsilon = 0.3; %random action choice
        load('DQN_weights.mat','-mat');
        estimator.set_weights(Weights);
    end
    timeStart = clock;
    for itr=1:NUM_ITERATIONS 
        env.reset([0 0]);  
        if ~isTraining
            env.reset(env.locA);  
            env.render();%display the moving environment
        end
        
        countActions = 0;%count how many actions in one iteration  
        reward = 0;
        done = false;
        state = env.current_location;
        
        while ~done   
            if countActions == maxItr
                break;
            end
            countActions = countActions + 1; 
            
            if ~isTraining
                values = estimator.predict(state).out_value;
                prob_a = make_epsilon_policy(values, epsilon);
                action = randsample(env.actionSpace,1,true,prob_a);      
            
                [next_state, reward, done] = env.step(action);
                
                state = next_state;
                env.render();%display the moving environment
                continue;
            end
    
            values = estimator.predict(state).out_value;
            prob_a = make_epsilon_policy(values, max(epsilon^log(itr),min_epsilon));
            action = randsample(env.actionSpace,1,true,prob_a);      
            
            [next_state, reward, done] = env.step(action);
    
    %         target = reward;
    %         if ~done
    %                 target = reward + gamma*max(estimator.predict(next_state).out_value);
    %         end
    %         estimator.update(state,action,target);
            memory_buffer(2:memory_size) = memory_buffer(1:memory_size-1);
            memory_buffer(1).state = state;
            memory_buffer(1).action = action;
            memory_buffer(1).next_state = next_state;
            memory_buffer(1).reward = reward;
            memory_buffer(1).done = done;
            memory_cnt = memory_cnt + 1; 
            
            state = next_state;
        end
        fprintf('%d th iteration, %d actions taken, final reward is %d.\n',itr,countActions,reward);
        if isTraining
            iterationCount(itr) = countActions;
            rwd(itr) = reward;
            %memory replay
            if memory_cnt >= memory_size
                mini_batch = randsample(memory_buffer,batch_size);
                for i=1:batch_size
                    tem_state = mini_batch(i).state;
                    tem_action = mini_batch(i).action;
                    tem_next_state = mini_batch(i).next_state;
                    tem_reward = mini_batch(i).reward;
                    tem_done = mini_batch(i).done;
                    tem_next_state_values = estimator.predict(tem_next_state).out_value;
                    tem_target = tem_reward;
                    if ~tem_done
                        tem_target = tem_reward + gamma*max(tem_next_state_values);
                    end
                    estimator.update(tem_state,tem_action,tem_target);
                end
            end
        end
    end
    if isTraining
        timeEnd = clock;
        timeDiff = sum([timeEnd - timeStart].*[0 0 0 3600 60 1]);
        simulationTime = [timeStart timeEnd timeDiff];
        save('DQN_simulationTime.mat','simulationTime'); 
        Weights = estimator.weights;
        save('DQN_weights.mat','Weights');
        save('DQN_iterationCount.mat','iterationCount');
        save('DQN_reward.mat','rwd');
        figure,bar(iterationCount)
        figure,bar(rwd)
    end
    
    
    
    
    展开全文
  • MATLAB强化学习入门——四、用DQN实现网格迷宫算例

    千次阅读 多人点赞 2020-03-05 15:32:06
    MATLAB强化学习入门》的第四期,我们尝试实现DQN网格迷宫算例的MatLab编程。主要内容可以分为两部分:①讨论DQN的算法核心思想,即DQN如何在Q学习的基础上使用神经网络代替Q表;②分享DQN网格迷宫的MatLab编程实现...

    上期我们聊了两个小问题,第一是为什么需要深度Q学习,第二则是MatLab神经网络工具箱的使用。那么本期,我们就尝试将DQN移植到第二期我们完成的Q-Learning网格迷宫程序中,尝试深度Q学习的算例实现。

    一、Deep-Q-Network算法核心

    总的来说,DQN的核心思想就是使用一个深度神经网络模型代替Q表来实现智能体对状态的估计。那么,这种替代就需要实现以下几个核心的功能:

    1. 在Q-Learning中,智能体以‘状态-动作对’为索引在Q表中获得对该状态-动作对的价值估计——Q函数值。对应的,在DQN中,我们希望神经网络能以状态-动作对为输入,以Q函数值为输出。
    2. 之所以Q-Learning、Sarsa等算法最终能够得到对状态的准确估计,原因在于这些算法在智能体运动时始终对Q函数表进行迭代。在DQN中,我们采用类似的思想,利用下一状态和奖赏获得目标Q值(Q_target),与神经网络当前得到的Q值(Q_eval)进行比较;随后将两者的误差通过梯度下降法反向传播回神经网络中,从而实现Q-Network的训练与更新。

    而为了实现Q-Network准确而高效的训练与更新,DQN算法的迭代策略展现出了两个重要区别:记忆重现(Replay Memory)固定目标网络(Fixed Q Target)
    记忆重现是指:不同于Q-Learning里智能体会在每行动一步后即对对应Q值进行更新,我们将智能体所经历的状态、动作、次状态均记录在一个记忆回放的存储区内,间隔一定的运动步数方才更新神经网络。更新神经网络时,从ReplayMemory中取一定量的‘状态-动作-次状态对’计算次状态的最大Q值以及回报,从而得到对应目标Q值(Q_target)。最后将这一批(batch)数据统一输入神经网络中进行训练。由于ReplayMemory是独立于神经网络的存在,这保证了训练数据的相对独立性。也因此,一方面,神经网络模型不会在训练时因为最近几次可能的错误尝试而“练偏”;另一方面,我们甚至可以在ReplayMemory中添加筛选好的或者其它智能体的训练数据来训练当前神经网络。
    固定目标网络则将Q-Network构成的“Q表”分成了两份,一份在智能体选择动作时使用,另一份则在智能体计算Q_target的时候使用。在程序初始化的时候,计算Q_target的目标网络与选择动作的评估网络是一致的。然而随后,目标网络的更新将滞后于评估网络:评估网络每更新数次,我们才将评估网络的参数赋给目标网络,实现目标网络的更新。从理论上将,这一方法能够提高算法的稳定性。
    下图即用伪代码的形式展示了算法从Q-Learning变化至Deep-Q-Network的主要变更。变化主要体现在三部分,分别是:①神经网络模型及对应结构的初始化,②利用神经网络选择动作,③存储状态等信息并训练更新神经网络。

    下图即用伪代码的形式展示了算法从Q-Learning变化至Deep-Q-Network的主要变更。变化主要体现在三部分,分别是:①神经网络模型及对应结构的初始化,②利用神经网络选择动作,③存储状态等信息并训练更新神经网络
    在这里插入图片描述

    图1 DQN算法与Q-Learning算法的主要差异

    而上图算法中没能展现出来的,还有DQN的另一个要点,就是DQN训练的分期。DQN的训练是依赖数据的,而程序初始化以后显然没有能够供DQN进行训练的数据。因此,我们在训练期之前需要设置一个观察期。在观察期内,智能体仅执行动作,不训练网络。从而在训练期初期,有足够的数据供神经网络训练。

    二、 网格迷宫MatLab程序实现

    在对算法有了足够的了解后,我们即可用流程图来分析网格迷宫算例的实现。我们将程序拆分为三个主要的执行阶段,分别是参数的初始化、观察期的执行与训练期的执行。
    在这里插入图片描述

    图2 DQN网格迷宫流程图

    2.1 程序初始化

    参数初始化阶段,我们需要完成环境参数、智能体参数、训练记录和动态绘图的初始化。首先是网格迷宫的有关参数,这些参数与Q-Learning算例中的参数是在形式上是一致的。然而既然使用了神经网络模型,我们不妨将迷宫的规模扩大一些,变为60×35的。另外,我们将迷宫大小等重要常参数设置为全局变量,以方便不同函数之间的调用。
    随后我们使用fitnet()生成一个共两层,每层40个神经元的初始化神经网络。从这里我们可以看到,由于算例简单,我们实际上并不需要复杂的多层的神经网络来进行计算,简单的神经网络也能够满足运算。在该算例下,实际上并不存在DQN,而仅仅是Q-Network,随后的倒立摆问题亦是如此。虽然DQN在实际的设计过程中不仅需要优化神经网络结构,还需要详细考虑训练方式以提高效率,但其算法的核心思想与本篇所讨论的内容是几乎一致的。这也是为什么,在笔者所学习的资料以及本文中,使用的是一种非深度神经网络去讨论DQN的算法并实现算例。
    初始化神经网络
    后,我们还需要定义一个数据集训练神经网络以规定其输入和输出。最后将训练方法设计为梯度下降法,并关闭训练图窗(不停的跳出来实在是有点儿烦)。
    初始化阶段最后的任务是生成动态绘图需要的数据结构并调用动态绘图指令,原因在于,在MatLab中,调用神经网络执行算例后,计算时间大大增加。我们没必要等到10000次训练结束后再分析结果,而可以用动态绘图的方式在程序运行的过程中即对程序是否编写正确进行判断。

    clear all;
    %定义全局参数,方便函数调用
    global Gwidth Gheight N_act targetxy gamma;
    
    %网格迷宫参数
    Gwidth=60;
    Gheight=35;
    N_act=4;
    %风速初始化
    Windyworld.windx=zeros(Gheight,Gwidth);
    Windyworld.windy=zeros(Gheight,Gwidth);
    Windyworld.windy(:,6:9)=Windyworld.windy(:,6:9)+1;   %%Windyworld.windy(:,7:8)=Windyworld.windy(:,7:8)+1;
    targetxy=[10,14];                 %!!注意:第一个坐标为y坐标,第二个坐标为x坐标 
    startxy=[1,4];
    step=1;
    
    %时间设置:观察期,训练期
    T_obs=500;                      
    T_train=10000;
    T_episode=200;
    
    %DQN神经网络初始化
    QNet_eval=fitnet([40,40]);
    Iniset=zeros(4,400);  %前三行为输入,最后一行为目标输出
    for i=1:40
        Iniset(1,i)=unidrnd(Gheight);
        Iniset(2,i)=unidrnd(Gwidth);
        Iniset(3,i)=unidrnd(N_act);
        if Iniset(3,i)==1
            Iniset(4,i)=0.2;
        
        else if Iniset(3,i)==2
                Iniset(4,i)=-0.2;
            end
            %}
        end
    end
    clear i;
    QNet_eval=train(QNet_eval,Iniset(1:3,:),Iniset(4,:));
    QNet_target=QNet_eval;
    %将神经网络训练算法设置为自适应动量梯度下降法
    QNet_eval.trainFcn='traingdx';  
    %关闭训练图窗nntraintool
    QNet_eval.trainParam.showWindow=0;
    
    
    %Replaymemory初始化:
    S_memo=8000;
    Rmemo=zeros(5,S_memo);    %1:2:rolexy,3:act,4:5:nextxy
    Memopointer=1;  %Replay memory的写入指针
    
    %学习参数初始化
    gamma=0.99;      
    nBatch=400;
    T_gap=400;   %20,25,30
    T_renew=3*T_gap;
    
    %记录列表初始化
    Successmark=zeros(1,T_obs+T_train);
    AveSuccess=zeros(1,T_obs+T_train);
    TotalSuccess=zeros(1,T_obs+T_train);
    
    %动态绘图初始化
    Plotset=zeros(2,1);
    p = plot(Plotset(1,:),Plotset(2,:),...
       'EraseMode','background','MarkerSize',5);
    axis([0 T_obs+T_train 0 1]);
    
    

    2.2 观察期与训练期:优化执行效率

    观察期和训练的代码几乎一致,区别仅在于训练神经网络的部分。**在第三期里,我们讨论过神经网络调用效率的问题。简而言之,在MatLab中,调用神经网络400次计算400个输入的耗时将远高于一次使用神经网络计算400个输入。**在网格迷宫里,我们需要在两个地方调用神经网络,第一是在tcegreedy()函数中选择动作,第二是在获得次状态后计算Q_target.
    在tcegreedy()函数中,我们需要计算当前状态下4个动作的Q值并选择其中Q值最大的动作作为输出。在tcegreedy()内部,我们需要将4个动作的输入拼接起来一次性输入神经网络中以提高效率;而在tcegreedy()外部,由于智能体执行动作并与环境交互的顺序性不能改变,我们只能一次次调用tcegreedy()而没法再提高调用效率了。
    然而,计算Q_target的过程存在大幅提高调用效率的可能。由于神经网络的训练是存在间隔和采样批次的,我们没必要在每获得一个新状态后就立刻计算Q_target,而可以在ReplayMemory中记录‘状态-动作-次状态对’。在训练前从ReplayMemory中采样,一次性输入到QNet中获得次状态Q值以计算Q_target。这就是函数CalculationQtarget()的由来。

    %观察期:此期间不更新Qnet,仅记录replay memory
    for Ts=1:T_obs
        rolexy=startxy;
        %result(Ts).trace=zeros(40,3);
        %result(Ts).trace(1,:)=([1,rolexy(1),rolexy(2)]);
        for Tm=1:T_episode
          %根据tcegreedy策略执行动作
            [act,Q_now]=tcegreedy(Ts,rolexy,QNet_eval);
            nextxy=movement(act,rolexy,Windyworld);
          %Replaymemory记录+指针更新
            Rmemo(:,Memopointer)=[rolexy';act;nextxy'];
            Memopointer=PointerMove(Memopointer,S_memo);
          %更新位置
            step=step+1;
            rolexy=nextxy;
            %result(Ts).trace(Tm+1,:)=([Tm+1,rolexy(1),rolexy(2)]);
                %判断是否跳出本episode
            if rolexy(1)==targetxy(1)&&rolexy(2)==targetxy(2)
                Successmark(Ts)=1;
                break;
            else if rolexy(1)<1||rolexy(1)>Gheight||rolexy(2)<1||rolexy(2)>Gwidth
                    break;
                end
            end    
        end
        %数据记录
        TotalSuccess(Ts)=sum(Successmark(1:Ts));
        AveSuccess(Ts)=TotalSuccess(Ts)/Ts;
        %动态绘图
        if mod(Ts,10)==0
            TempP=[Ts;AveSuccess(Ts)];
            Plotset=[Plotset,TempP];
            set(p,'XData',Plotset(1,:),'YData',Plotset(2,:));
            drawnow
            axis([0 T_obs+T_train 0 1]);             
        end
    end
    
    %探索期
    %探索期开始更新神经网络参数
    Tnode1=1+T_obs;
    Tnode2=T_obs+T_train;
    %网络训练参数更新
    for Ts=Tnode1:Tnode2
        rolexy=startxy;
        %result(Ts).trace=zeros(40,3);
        %result(Ts).trace(1,:)=([1,rolexy(1),rolexy(2)]);
        for Tm=1:T_episode
          %根据tcegreedy策略执行动作
            [act,Q_now]=tcegreedy(Ts,rolexy,QNet_eval);
            nextxy=movement(act,rolexy,Windyworld);
          %为提高效率,Q_target统一在训练神经网络时更新
          %Replaymemory记录+指针更新
            Rmemo(:,Memopointer)=[rolexy';act;nextxy'];
            Memopointer=PointerMove(Memopointer,S_memo);
          %更新位置
            step=step+1;
            rolexy=nextxy;
            %result(Ts).trace(Tm+1,:)=([Tm+1,rolexy(1),rolexy(2)]);
            %判断是否跳出本episode
            if rolexy(1)==targetxy(1)&&rolexy(2)==targetxy(2)
                Successmark(Ts)=1;
                break;
            else if rolexy(1)<1||rolexy(1)>Gheight||rolexy(2)<1||rolexy(2)>Gwidth
                    break;
                end
            end
            
          %按照T-renew间隔更新估计Q_target的目标神经网络QNet_target  
           if mod(step,T_renew)==0
               QNet_target=QNet_eval;
           end
           
           %按照T_gap的间隔训练估计Q_eval的评估神经网络QNet_eval
           if mod(step,T_gap)==0
               %1. 利用Rmemo生成训练数据级
               Trainset=zeros(6,nBatch);  %前五行与replaymemory一致,后一行为利用QNet_target计算得到的Q_target
               i=1;
               while i<=nBatch
                   num1=unidrnd(S_memo);  %随机抽取ReplayMemory中的数据
                   if Rmemo(1,num1)>0
                       Trainset(1:5,i)=Rmemo(:,num1);
                       i=i+1;
                   end
               end
               %2. 计算Q_target
               Trainset(6,:)=CalculationQtarget(Trainset(1:5,:),QNet_target);
               %3. 训练QNet_eval
               QNet_eval=train(QNet_eval,Trainset(1:3,:),Trainset(6,:));
           end
        end    
    
        %数据记录
        TotalSuccess(Ts)=sum(Successmark(1:Ts));
        AveSuccess(Ts)=TotalSuccess(Ts)/Ts;
        %动态绘图
        if mod(Ts,10)==0
            TempP=[Ts;AveSuccess(Ts)];
            Plotset=[Plotset,TempP];
            set(p,'XData',Plotset(1,:),'YData',Plotset(2,:));
            drawnow
            axis([0 T_obs+T_train 0 1]);             
        end
    end
    

    2.3 Let it RUN

    以上,我们就介绍了在MATLAB中使用DQN算法实现网格迷宫算例的编程要点。
    Let it run and show the result.
    在这里插入图片描述我们展示DQN两个训练周期里的表现,Test1中,训练到3000左右时,智能体的表现突然下滑,这可能是神经网络过拟合造成的,也可能是不良训练样本训练造成的影响。Test2则表现出了较为正常的训练情况,曲线也与Q_Learning类似。

    以上,我们就讨论完了《MatLab强化学习入门》第四期的所有内容。本期我们使用DQN解决网格迷宫问题的完整代码,已经和第五期解决倒立摆问题的代码合并上传,读者可以移步以下链接下载:

    MATLAB强化学习_神经网络控制_倒立摆问题&网格迷宫问题

    十分欢迎有心读本文的CSDNer交流讨论;如果觉得本文有帮助的话,打赏一下可是更好(๑•̀ㅂ•́)و✧

    展开全文
  • MATLAB强化学习入门》的第五期,讨论倒立摆的DQN神经网络控制问题,包括倒立摆的数学建模、DQN强化学习以及总的程序实现。

    在上一期中,使用DQN算法,我们让智能体能够顺利解决较大的网格迷宫问题。本期我们更进一步,尝试用DQN控制倒立摆。倒立摆是非常经典的控制问题,如果DQN能够有效实现倒立摆的控制,也就意味着DQN等强化学习算法适用于更复杂的动力学控制问题,即就是说,采用相似的思想,我们可以将强化学习算法用于机械臂控制、卫星姿态控制等工程问题上。

    像往常一样,想要实现倒立摆的强化学习控制,我们可以把这样一个大问题拆解成几个相对独立的问题解决。第一是使用MatLab实现倒立摆的数值仿真建模;第二则是修改DQN算法,使之能够与倒立摆环境相适应;第三则是改善程序的整体框架,使它更简洁、更易于维护。

    第一个问题中,倒立摆的动力学方程可以整理为常微分方程;同时,为了更好的与之前我们掌握的神经网络工具箱结合,我们使用MatLab的Ode45()函数实现动力学仿真。
    第二个问题,我们需要根据倒立摆问题调整神经网络和DQN算法的相关参数,使之能够满足控制需求。这其中,神经网络的输入、输出参数需要得到调整;DQN算法中的回报(reward)需要修改;训练循环的计数方式以及训练周期等内容也需要调整。
    最后,由于整个程序中加入了倒立摆的数值仿真,不仅参数和常数增多,程序也相对网格迷宫程序复杂了很多。因此,我们需要优化程序的编写,以提高程序的易读性和维护性。

    一、倒立摆的数学建模

    1.1 倒立摆模型的方程

    在这里插入图片描述
    倒立摆由小车以及小车上向上铰支的摆杆组成,显然,当摆杆朝上时,这是一个可以平衡但不能稳定的系统。
    小车固定在横轴上,因此在y方向上无位移,仅在x方向上有位移和速度。在水平方向上,小车受到控制力、摩擦力以及摆杆支撑力水平分量的作用。取x_c为x方向位移、x_c为x方向速度,得方程(1.1):
    在这里插入图片描述
    至于摆杆,虽然摆杆的下端固定在小车上,但摆杆的质心却是存在垂直和水平两向位移的。水平方向上,摆杆受力为支撑力的水平分量;垂直方向上,摆杆的受力包括重力和支撑力的垂直分量。
    在这里插入图片描述
    除此之外,摆杆存在转动,绕质心的转动方程为:
    在这里插入图片描述
    然而,上述动力学系统中,四个物理坐标仅仅有两个是相互独立的,
    因此,在实际的数值仿真中,为了更好的与物理现象相对应,我们选取小车的横坐标x_c和摆杆的转角θ作为状态量。摆杆质心的横纵坐标与x_c及θ的关系如下:
    在这里插入图片描述
    小车所收到的摩擦力与运动方向相反,与相对滑轨的正压力成正比,摩擦力F_f可表示为:
    在这里插入图片描述
    联立上述方程,即可得到用于适合于数值求解的方程格式:
    在这里插入图片描述

    1.2倒立摆的数值仿真

    如上,即完成了倒立摆的数值仿真建模。我们将方程在编程中实现,并调用ode45()函数,即可实现倒立摆的MatLab仿真。

    [t,y]=ode45(@CartPole_Eqs,[0,T_step],OdeInput,opts);
    
    function dotPara=CartPole_Eqs(t,Para)
    global Mc Mp Lp Cf g;
    X=Para(1);
    V=Para(2);
    Theta=Para(3);
    Omega=Para(4);
    Fc=Para(5);
    dotPara=zeros(4,1);
    
    dotPara(1,:)=V;
    
    
    if V~=0
        D1=V/abs(V);
    else
        D1=0;         %停滞状态下不考虑摩擦力,实际上,除去初值外,dotx几乎不为0
    end
    C21=(Mc+Mp)/Mc+3/4*Mp/Mc*cos(Theta)*(Cf*D1*sin(Theta)-cos(Theta));
    C22=Fc/Mc-(Mp+Mc)/Mc*Cf*D1*g+(sin(Theta)+cos(Theta)*Cf*D1)*Mp/Mc*Lp/2*(Omega^2)+0.75*(Cf*D1*sin(Theta)-cos(Theta))*Mp/Mc*sin(Theta)*g;
    dotPara(2,:)=C22/C21;
    
    dotPara(3,:)=Omega;
    dotPara(4,:)=1.5/Lp*(sin(Theta)*g-cos(Theta)*dotPara(2));
    dotPara(5,:)=0;
    

    二、倒立摆的DQN控制

    想要使用DQN控制倒立摆,有两个问题需要解决。第一,是DQN的状态和动作分别是什么?第二,DQN的奖赏如何定义?
    对于第一个问题,DQN的状态就是倒立摆动力学系统的状态,包括四个参量,小车的横坐标、水平速度,摆杆的转角以及旋转角速度。对于DQN的动作,我们知道倒立摆的平衡是由控制力F_c实现的,因此其动作自然应该是控制力。但控制力本身是连续量,在依据策略选择动作时我们没办法将这一连续量的所有值都遍历一遍以获得Q值最大的控制力。因此,**我们将倒立摆的控制力离散化成一个控制力数组来实现DQN需要的动作输入,**也就是说,倒立摆的控制力输出为一组规定的常值。**在仿真模拟中,智能体每隔规定间隔进行一次状态采样,输入DQN网络中获得该状态下所有动作的Q值并选择Q值最高的动作,此控制力即为下一时间段的控制力输出。**也就是说,由于DQN的特点,我们采用幅值和时间上均离散的控制力来实现倒立摆的控制。
    对于第二个问题,我们希望,倒立摆的小车水平位置距离导轨越近越好,摆杆如垂直方向的夹角越小越好。由于整个倒立摆控制程序中,需要在多个地方进行奖赏reward()的计算,我们将奖赏封装成如下的函数:

    function reward=Reward_Cal(CPstate)
    global X_threshold Theta_threshold;
    r1=1.4*((X_threshold-abs(CPstate(1)))/X_threshold-0.8);
    r2=(Theta_threshold-abs(CPstate(3)))/Theta_threshold-0.95;
    reward=r1+r2;
    

    奖赏的定义对DQN控制器的表现存在着较大的影响,r1与r2的权重决定了DQN对两种位置误差的敏感程度。也因此,奖赏的定义本身也是倒立摆DQN控制中可以调试的参数。读者也可尝试对奖赏函数进行修改来观察DQN的表现。

    三、 倒立摆程序设计

    我们修改在网格迷宫中搭建的MatLab程序框架,以实现其对倒立摆的控制。变化主要有以下几点:

    1. 由于神经网络智能体和倒立摆环境参数较多,参数的初始化单独用两个.m文件封装,这样也方便了参数的调整与检查。
    2. 将观察期和训练期合并成了一段代码,缩短代码长度,便于检查和维护。
    3. 单训练周期内,循环变量由次数变为时间,且时间的步进为可调参数。
    4. 在每个episode的开始,倒立摆的初始化会产生随机的扰动,一方面提高训练中的“探索”概率,另一方面模拟真实情况。
      程序的框架可由下面的流程图展示。
      在这里插入图片描述程序的主体部分则如下:
    % 忘记面孔的Batou
    % "I thought what I'd do was I'd pretend I was one of those deaf-mutes, or should I?" 
    
    clear all;
    
    run('CartPoleInitializer');  
    run('AgentInitializer'); 
    
    %训练周期设置:观察期,训练期
    N_obs=300;                       
    N_train=3000;
    N_total=N_obs+N_train;
    T_episode=60;           %每个周期的总时间
    
    %数据记录初始化,状态记录在Episode开始前进行
    TimeRecord=zeros(1,N_total);
    AveTimeRecord=zeros(2,N_total/10);
    ATRpointer=1;
    
    %episode及其余设置
    T_step=0.1;
    n_step=1;
    
    %动态绘图初始化
    Plotset=zeros(2,1);
    p = plot(Plotset(1,:),Plotset(2,:),...
       'EraseMode','background','MarkerSize',5);
    axis([0 N_obs+N_train 0 60]);
    
    
    
    for Ns=1:N_total
        CPstate=CartPoleReset();                %CPstate为4*1矩阵,x,dotx,theta,dottheta
        T1=0;
        %初始化历史记录。记录下列内容:1.控制时长;2.每个episode的600个状态与控制力矩
        TrackPointer=1;
        TrackRecord(Ns).Track=zeros(6,T_episode/T_step);
        while T1<=T_episode
            %根据tcegreedy策略选择动作
            [act,Qnow]=tcegreedy(Ns,CPstate,QNet_eval);  
            Fc=FcTable(act);
            %使用Ode45执行动作
            OdeInput=[CPstate;Fc];
            [t,y]=ode45(@CartPole_Eqs,[0,T_step],OdeInput,opts);
            Nsize=size(y); Nsize=Nsize(1);
            Newstate=y(Nsize,1:4); Newstate=Newstate';
            %Replaymemory记录+指针更新
            Rmemo(:,Memopointer)=[CPstate;act;Newstate];
            Memopointer=PointerMove(Memopointer,S_memo);
            %轨迹数据记录更新
            TrackRecord(Ns).Track(:,TrackPointer)=[T1;CPstate;Fc];
            TrackPointer=TrackPointer+1;
            %更新状态
            T1=T1+T_step;
            n_step=n_step+1;
            CPstate=Newstate;       
            
            %按照T-renew间隔更新估计Q_target的目标神经网络QNet_target
            if (mod(n_step,N_renew)==0)&&(Ns>=N_obs)
                QNet_target=QNet_eval;
            end
            
            %按照T_gap的间隔训练估计Q_eval的评估神经网络QNet_eval
            if (mod(n_step,N_gap)==0)&&(Ns>=N_obs)
                %1. 利用Rmemo生成训练数据级
                Trainset=zeros(10,nBatch);      %前9行与replaymemory一致,后一行为利用QNet_target计算得到的Q_target;
                i=1;
                while i<=nBatch
                    num1=unidrnd(S_memo);
                    if Rmemo(5,num1)>0          %有记录的第五行始终不为零
                        Trainset(1:9,i)=Rmemo(:,num1);
                        i=i+1;
                    end
                end
                %2. 计算Q_target
                Trainset(10,:)=CalculationQtarget(Trainset(1:9,:),QNet_target);            
                %3. 训练QNet_eval
                QNet_eval=train(QNet_eval,Trainset(1:5,:),Trainset(10,:));
            end
            %判断是否跳出本episode,并记录控制时长
            if (abs(CPstate(1))>X_threshold)||(abs(CPstate(3))>Theta_threshold)
                TimeRecord(Ns)=T1;
                break;
            elseif T1>=T_episode
                TimeRecord(Ns)=T1;
                break;
            end
        end
        %动态绘图
        if mod(Ns,10)==0
            Ave1=mean(TimeRecord(Ns-9:Ns));
            AveTimeRecord(:,ATRpointer)=[Ns;Ave1]';
            ATRpointer=ATRpointer+1;        
            TempP=[Ns;Ave1];
            Plotset=[Plotset,TempP];
            set(p,'XData',Plotset(1,:),'YData',Plotset(2,:));
            drawnow
            axis([0 N_obs+N_train 0 60]);             
        end
        
    end
    

    四、Let it RUN

    完成程序后,我们运行程序以观察智能体的训练。在倒立摆模型中,我们不能再简单的以智能体是否到达终点作为性能评估的标识,而以每一个episode中DQN控制倒立摆不倒(小车的坐标距离中心的偏差和摆杆的转角均不超过门限)的时长作为观察其性能的标志。我们取每10个Episode的控制时长作平均进行绘图,得到DQN的训练情况:
    在这里插入图片描述在训练完成后,单个Episode里,倒立摆呈现出如下的运动状态:
    在这里插入图片描述

    以上,即是《MatLab强化学习入门》第五期的内容。本期我们使用DQN解决倒立摆问题的完整代码,已经和第四期解决网格迷宫问题的代码合并上传,读者可以移步以下链接下载:MATLAB强化学习_神经网络控制_倒立摆问题&网格迷宫问题

    十分欢迎有心读本文的CSDNer交流讨论;如果觉得本文有帮助的话,打赏一下可是更好(๑•̀ㅂ•́)و✧

    展开全文
  • 使用DQN训练摆锤系统钟摆模型创建环境接口创建DQN智能体训练智能体智能体仿真 此示例显示了如何建立钟摆模型并使用深度Q学习网络(DQN)训练。 钟摆模型 这个例子的强化学习环境是一个简单的无摩擦的钟摆,最初挂在...


    此示例显示了如何建立钟摆模型并使用深度Q学习网络(DQN)训练。

    钟摆模型

    在这里插入图片描述

    这个例子的强化学习环境是一个简单的无摩擦的钟摆,最初挂在一个向下的位置。训练的目标是使用最小的控制努力使钟摆站直而不跌倒。

    打开模型

    mdl = 'rlSimplePendulumModel';
    open_system(mdl)
    

    在这里插入图片描述
    对于这个模型:

    1. 平衡摆向上位置为0弧度,向下悬挂位置为π\pi弧度。
    2. 从智能体到环境的扭矩作用信号为–2至2 N·m。
    3. 从环境中观察到的是摆角的正弦,摆角的余弦和摆角导数。
    4. 每一步都会提供奖励rtr_t

    在这里插入图片描述
    在这里:

    1. θt\theta_t是从直立位置开始的位移角度。
    2. θt˙\dot{\theta_t}是位移角的导数。
    3. ut1u_{t-1}是上一个时间步的控制工作。

    创建环境接口

    为钟摆创建一个预定义的环境界面。

    env = rlPredefinedEnv('SimplePendulumModel-Discrete')
    

    在这里插入图片描述
    界面具有离散的操作空间,智能体可以在其中将三个可能的扭矩值之一施加到摆锤上:–2、0或2 N·m。
    要将摆的初始条件定义为向下悬挂,请使用匿名函数句柄指定环境重置函数。 此重置功能将模型工作区变量thetaθ\theta设置为pi。

    env.ResetFcn = @(in)setVariable(in,'theta0',pi,'Workspace',mdl);
    

    从环境获取观察和动作规范信息

    obsInfo = getObservationInfo(env)
    

    在这里插入图片描述

    actInfo = getActionInfo(env)
    

    在这里插入图片描述
    以秒为单位指定模拟时间Tf和智能体采样时间Ts。

    Ts = 0.05;
    Tf = 20;
    

    固定随机生成器种子以提高可重复性。

    rng(0)
    

    创建DQN智能体

    DQN智能体使用值函数作为评论者,根据观察和行动,去近似长期奖励。

    由于DQN具有离散的动作空间,因此它可以依靠多输出评论者逼近器,这通常比依靠可比的单输出逼近器更有效。 多输出逼近器仅将观测值作为输入,而输出矢量则具有与可能的离散操作数一样多的元素。 当采取相应的离散操作时,每个输出元素代表从输入观察得出的预期长期累积奖励。

    要创建评论者,请首先创建一个深度神经网络,该网络具有三个元素的输入矢量(用于摆角的正弦,余弦和导数),以及一个具有三个元素的输出矢量(–2、0或2 Nm动作) 。有关创建深度神经网络值函数表示的更多信息,请参见创建策略和值函数表示

    dnn = [
        featureInputLayer(3,'Normalization','none','Name','state')
        fullyConnectedLayer(24,'Name','CriticStateFC1')
        reluLayer('Name','CriticRelu1')
        fullyConnectedLayer(48,'Name','CriticStateFC2')
        reluLayer('Name','CriticCommonRelu')
        fullyConnectedLayer(3,'Name','output')];
    

    查看评论者网络配置。

    figure
    plot(layerGraph(dnn))
    

    在这里插入图片描述
    使用rlRepresentationOptions指定评论者表示的选项。

    criticOpts = rlRepresentationOptions('LearnRate',0.001,'GradientThreshold',1);
    

    使用指定的深度神经网络和选项创建评论者表示。 您还必须为评论者指定观察和动作信息。有关更多信息,请参见rlQValueRepresentation

    critic = rlQValueRepresentation(dnn,obsInfo,actInfo,'Observation',{'state'},criticOpts);
    

    要创建DQN智能体,请首先使用rlDQNAgentOptions指定DQN智能体选项。

    agentOptions = rlDQNAgentOptions(...
        'SampleTime',Ts,...
        'TargetSmoothFactor',1e-3,...
        'ExperienceBufferLength',3000,... 
        'UseDoubleDQN',false,...
        'DiscountFactor',0.9,...
        'MiniBatchSize',64);
    

    然后,使用指定的评论者表示形式和智能体选项创建DQN智能体。 有关更多信息,请参见rlDQNAgent

    agent = rlDQNAgent(critic,agentOptions);
    

    训练智能体

    要训练智能体,请首先指定训练选项。对于此示例,使用以下选项。

    1. 每次训练最多进行1000个episodes,每个情节最多可以持续500时间。

    2. 在“情节管理器”对话框中显示训练进度(设置Plots选项),并禁用命令行显示(将Verbose选项设置为false)。

    3. 当智能体连续五个episodes获得的平均累积奖励大于–1100时,请停止训练。在这一点上,智能体可以以最小的控制力快速地使摆锤处于直立位置。

    4. 为累积奖励大于–1100的每个episode保存智能体的副本。

    trainingOptions = rlTrainingOptions(...
        'MaxEpisodes',1000,...
        'MaxStepsPerEpisode',500,...
        'ScoreAveragingWindowLength',5,...
        'Verbose',false,...
        'Plots','training-progress',...
        'StopTrainingCriteria','AverageReward',...
        'StopTrainingValue',-1100,...
        'SaveAgentCriteria','EpisodeReward',...
        'SaveAgentValue',-1100);
    

    使用训练函数训练智能体。 训练此智能体是一个计算密集型过程,需要几分钟才能完成。 为了节省运行本示例的时间,请通过将doTraining设置为false来加载预训练的智能体。 要自己训练智能体,请将doTraining设置为true。

    doTraining = false;
    
    if doTraining
        % Train the agent.
        trainingStats = train(agent,env,trainingOptions);
    else
        % Load the pretrained agent for the example.
        load('SimulinkPendulumDQNMulti.mat','agent');
    end
    

    在这里插入图片描述

    智能体仿真

    要验证训练有好的智能体的表现,请在摆环境中对其进行仿真。 有关智能体模拟的更多信息,请参见rlSimulationOptionssim

    simOptions = rlSimulationOptions('MaxSteps',500);
    experience = sim(env,agent,simOptions);
    

    在这里插入图片描述

    展开全文
  • 使用并行计算训练DQN智能体进行车道保持辅助[LKA]DQN并行训练概述Ego Car 的 Simulink 模型创建环境接口创建DQN智能体训练选项并行计算选项训练智能体DQN智能体仿真 此示例显示了如何使用并行训练在Simulink®中训练...

空空如也

空空如也

1 2 3 4
收藏数 63
精华内容 25
关键字:

dqnmatlab

matlab 订阅