首页 > 代码库 > 学习笔记TF037:实现强化学习策略网络

学习笔记TF037:实现强化学习策略网络

强化学习(Reinforcement Learing),机器学习重要分支,解决连续决策问题。强化学习问题三概念,环境状态(Environment State)、行动(Action)、奖励(Reward),目标获得最多累计奖励。强化学习模型根据环境状态、行动和奖励,学习出最佳策略,以最终结果为目标,不能只看某个行动当下带来的利益,还要看行动未来带来的价值。

AutoEncoder属于无监督学习,MLP、CNN、RNN属于监督学习,强化学习目标变化、不明确,或不存绝对正确标签。

Google DeepMind结合强化学习和深度学习,提出DQN(Deep Q-Network,深度Q网络)。AlphaGo结合策略网络(Policy Network)、估值网络(Value Network,DQN)、蒙特卡洛搜索树(Monte Carlo Tree Search)。

无人驾驶是非常复杂、困难强化学习任务。无人驾驶汽车通过摄像头、雷达、激光测距仪、传感器观测环境,获取丰富环境信息,深度强化学习模型CNN、RNN处理、抽象、转化环境信息,结合强化学习算法框架预测最应执行动作(加速、减速、转换方向),实现自动驾驶。每次执行动作,到目的地路程更短,作为每次行动奖励。最终目标是安全顺利到达目的地,得到奖励最多。

强化学习两大类,Policy-Based(Policy Gradients)和Value-Based(Q-Learning)。Policy-Based直接预测环境状态下应采取Action,Value-Based预测环境状态下所有Action期望价值(Q值),选择Q值最高Action执行。Value-Based适合少量离散取值Action,Policy-Based适合Aciton种类多或连续取值Action环境。Policy Network、Value Network。

根据环境状态和采取行动预测后续环境状态,利用信息训练强化学习模型,是Model-Based RL。Model-Free RL直接对策略或Action期望价值预测,计算效率高。复杂环境,主要用Model-Free RL,供给更多样本训练,弥补没有Model预测环境状态问题。

环境中,强化学习模型载体Agent,负责执行模型行动。环境,Agent无法控制,可以观察。根据观察结果,模型给出行动,Agent执行。Reward,环境状态下执行Action获得,模型争取目标。Reward延迟获到Delayed。Action即时获得Reward,和未来获得Reward有很大关系。

策略网络,建立神经网络模型,通过观察环境状态,直接预测目前最应该执行策略(Policy),执行策略获得最大期望收益(包括现在、未来Reward)。没有绝对正确学习目标,样本feature不再和label对应。特定环境状态,不知道对应最好Action,只知道当前Action获得Reward,试验后获得未来Reward,强化学习模型通过试验样本学习环境状态下比较好的Action。样本没有绝对正确label,只有估算label。策略网络,不只用当前Reward作label,用Discounted Future Reward,所有未来奖励依次乘以衰减系数y。衰减系数,略小于但接近1,防止没有损耗积累导致Reward目标发散,代表未来奖励不确定性估计。

Policy Gradients方法训练策略网络。模型通过学习Action在Environment获得反馈,用梯度更新模型参数。训练过程,模型接触到好Action及高期价值,和差Action及低期望价值。通过样本学习,模型逐渐增加选择好Action概率,降低选择坏Action概率,完成策略学习。直接学习当前环境应该采取策略,如选择Actionc概率,或Action具体数值。策略网络是End-to-End(端对端)方法,直接产生最终策略。

Policy-Based比Value-Based,收敛性更好,通常可以保证收敛到局部最优,且不会发散。对高维、连续值Action,训练、输出结果都更高效。能学习出带有随机性的策略。

Gym辅助策略网络训练。Gym,OpenAI开源强化学习环境生成工具。OpenAI,Tesla、Space X CEO Elon Musk发起非营利人工智能研究机构。研究安全、开放人工智能技术,确保人工智能技术广泛、公平普及服务社会。Gym,提供方便强化学习任务环境,强化学习算法效率、性能比较。Gym提供大量标准化环境,用来公平横向对比强化学习模型性能。Gym用户上传模型效果、训练日志到OpenAI Gym Service接口,参与任务排名,比较模型效果,分享算法思路。

OpenAI Gym,对用户开发模型方式无限制,和其他机器学习库完全兼容(TensorFlow、Theano)。可以用Python语言、任何Python Library编写强化学习模型Agent。如创建简单经验规则,使用State-Action一一对应策略表,深度神经网络模型训练。

Gym,两个核心概念。Environment,任务、问题。Agent,策略、算法。Agent将执行Action传给Environment,Environment接受Action,结果Observation(环境状态)和Reward返回Agent。Gym提供完整Environment接口,Agent完全由用户编写。Gym包含环境,Algorithmic(算法)、Atari游戏(Arcade Learning Environment)、Board Games(棋牌类游戏 Pachi)、Box2D(二维物理引擎)、Classic Control(经典控制)、MuJoCo(高效处理引擎)、Toy Text(文本类型)任务。执行full install安装全部环境依赖程序。

Gym环境接口,Env类。env=gym.make(‘Copy-v0‘)创建任务环境。env.reset()初始化环境,返回初始observation state。evn.step(action)当前状态执行一步Action,返回observation、reward、done(完成标记)、info(调试信息)。env.render()渲染一帧任务图像,Agent直接从图像像素学习信息策略。

Gym CartPole环境,《Neuronlike Adaptive Elements That Can Solve Difficult Learning Control Problem》,经典可用强化学习解决控制问题。CartPole环境有小车,一维无阻力轨道,行动。车上绑连接不太结实杆,左右摇晃。环境信息observation 是有4个值数组,包含小车位置、速度,杆角度、速度。不需要知道数值物理含义。设计策略网络,从数值学习环境信息,制定最佳策略。Action,小车施加正向力、负向力。Action Space,Action离散数值空间。CartPole Action Space,Discrete(2),只有0?1。只要模型学习到采取Action后带来的影响。Action只是编码。CartPole任务,尽可能保持杆竖直不倾倒,小车偏离中心超过2.4个单位距离,杆倾角超过15度,任务失败,自动结束。每坚持一步,reward+1。Reward恒定。模型要考虑到长远利益,不只是学习当前Reward。

env.reset()方法初始化环境,获取环境第一个Observation。根据Observation预测应该采取Action,用env.step(action),在环境中执行Action,返回Observation(CartPole 4维抽象特征)、reward(当前Action即时奖励)、done(任务是否结束标记,True,reset任务)、info(额外诊断信息)。进入Action-Observation循环,期望任务结束时尽可能高奖励。Action在CartPole离散数值空间,有限几种可能。别的任务可能是连续数值空间。环境名称后带版本号,环境发生更新或变化,不修改之前环境,创建新版本,Agent性能公平比较。调用env.monitor方法,监控、记录模型训练过程。gym.upload,训练日志上传到gym service展示,与他人算法比较。简单问题评测标准,需要多少步训练可以稳定达到理想分数。复杂问题评测标准,获得分数越高越好。

TensorFlow创建基于策略网络Agent,解决CartPole问题。先安装OpenAI Gym。pip install gym 。载入Numpy、TensorFlow、gym。gym.make(‘CartPole-v0‘)创建CartPole问题环境env。

先测试CartPole环境随机Action表现,作对比baseline。env.reset()初始化环境,10次随机试验,env.render()渲染CartPole问题图像。np.random.randint(0,2)产生随机Action。env.step()执行随机Action,获取返回observation、reward、done。如done标记为True,一次试验结束,倾角超过15度或偏离中心过远,任务失败。展示试验累计奖励reward_sum,重启环境。

随机策略奖励总值在10~40,均值在20~30。任务完成目标设定200 Reward,通过尽量少次数试验完成。

策略网络用简带一个隐含层MLP。设置网络超参数,隐含节点数H设50,bactch_size设25,学习速率learning_rate 0.1,环境信息observation维度D 4,gamma Reward discount比例0.99。估算Action期望价值(估算样本学习目标),考虑Delayed Reward,Action之后获得所有Reward做discount累加,让模型学习未来可能出现的潜在Reward。discount比例小于1,防止Reward无损耗累加导致发散,可以区分当前Reward和未来Reward价值,Action直接带来的Reward不需要discount,未来Reward存在不确定性需要discount。

定义策略网络结构,网络接受observation 输入信息,输出概率值,用以选择Action,向左施加力,向右施加力。创建输入信息observation placeholder,维度D。tf.contrib.layers.xavier_initializer初始化算法创建隐含层权重W1,维度[D,H]。tf.matmul,环境信息observation乘W1,用ReLU激活函数处理得到隐含层输出layer1,不加偏置。xavier_initializer算法创建最后Sigmoid输出层权重W2,隐含层输出layer1乘W2,Sigmoid激活函数处理得到最后输出概率。

模型优化器用Adam算法。设置两层神经网络参数梯度placeholder,W1Grad、W2Grad。adam.apply_gradients定义更新模型参数操作updateGrads。计算参数梯度,积累一定样本量梯度,传入W1Grad和W2Grad,执行updateGrads更新模型参数。深度强化学习训练用batch training。不逐个样本更新参数,累计一个batch_size样本梯度再更新参数,防止单一样本随机扰动噪声对模型带来不良影响。

定义函数discount_rewards,估算每个Action对就潜在价值discount_r。CartPole问题每次获得Reward和前面Action有关,属于delayed reward。需要比较精准衡量每个Action实际带来价值,不能只看当前这步Reward,要考虑后面Delayed Reward。让Pole长时间保持在空中竖直Action,应该有较大期望价值。最终导致Pole倾例Action,有较小期望价值。越靠后Acion期望价值越小,越靠前Acion期望价值越大。倒推过程,最后Action开始计算所有Action应该对应期望价值。输入数据r ,每个Action实际获得Reward,CartPole,最后结束时Action 0,其余 1。定义每个Action除直接获得Reward外,潜在价值running_add。running_add,从后向前累计,经过discount衰减。每个Action潜在坐,后一Action潜在价值乘以衰减系数gamma,加直接获得reward,running_add*gamma+r[t]。从最后Action,向前累计计算,得到全部Action潜在价值。

定义人工设置虚拟label placeholder input_y。每个Action潜在价值placeholder advangtages。loglik,Action取值 1概率probability(策略网络输出概率),Action取值 0概率 1-probability。label取值,label=1-Action。Action 1,label 0,loglik=tf.log(probability),Action取值为1的概率对数。Action 0,label 1,loglik=tf.log(1-probability),Action取值为0的概率对数。loglik,当前Action对应概率对数。loglik与潜在坐advantages相乘,取负数作损失,优化目标。优化器优化,能获得较多advantages Action概率变大,能获得较少advantages Action概率变小,损失变小。不断训练,持续加大能获得较多advantages Action概率,学习到一个能获得更多潜在价值策略。tf.trainable_variables()获取策略网络全部可训练参数tvars,tf.gradients求解模型参数 loss梯度。

定义参数,xs环境信息observation列表,ys label列表,drs记录每个Action Reward,reward_sum累计Reward,总试验次数total_episodes10000。达到200 Reward停止训练。

创建默认Session,初始化全部参数,一开始render标志关闭。render较大延迟,一开始不太成熟模型没必要观察。初始化CartPole环境,获得初始状态。sess.run执行tvars获取所有模型参数,创建储存参数梯度缓冲器gradBuffer,gardBuffer全部初始化零。每次试验收集参数梯度存储到gradBuffer,直到完成一个batch_size试验,汇总梯度更新模型参数。

试验循环,最大循环次数total_episodes。batch 平均Reward达到100以上,Agent表现良好,调用env.render()展示试验环境。tf.reshape将observation变形策略网络输入格式,传入网络,sess.run执行probability获得网络输出概率tfprob,Action取值1的概率。(0,1)间随机抽样,随机值小于tfprob,令Action取1,否则取0,Action取值 1概率为tfprob。

输入环境信息添加到列表xs,制造虚拟label——y,取值与Action相反,y=1-Action,添加到列表ys。env.step执行一次Action,获取observation、reward、done、info,reward 累加到reward_sum,reward添加到列表drs。

done为True,一次试验结束,episode_number加1。np.vstack 将列表xs、ys、drs元素纵向堆叠,得到epx、epy、epr,将xs、ys、drs清空,下次试验用。epx、epy、epr,一次试验中获得的所有observation、label、reward列表。discount_rewards函数计算每步Action潜在价值,标准化(减去均值再除以标准差),得零均值标准差1分布。dicount_reward参与模型损失计算。

epx、epy、discounted_epr输入神经网络,newGrads求解梯度。获得梯度累加gradBuffer。

试验次数达到batch_size整倍数,gradBuffer累计足够梯度,用updateGrads将gradBuffer中梯度更新到策略网络模型参数,清空gradBuffer,计算下一batch梯度准备。一个batch梯度更新参数,每个梯度是使用一次试验全部样本(一个Action一个样本)计算,一个batch样本数 25(batch_size)次试验样本数和。展示当前试验次数episode_number,batch内每次试验平均reward。batch内每次试验平均reward大于200,策略网络完成任务终止循环。如没达目标,清空reward_sum,重新累计下一batch总reward。每次试验结束,任务环境env重置。

模型训练日志,策略网络200次试验,8个batch训练和参数更新,实现目标,batch内平均230 reward。可以尝试修改策略网络结构、隐含节点数、batch_size、学习速率参数优化训练,加快学习速度。

    import numpy as np
    import tensorflow as tf
    import gym
    env = gym.make(CartPole-v0)
    env.reset()
    random_episodes = 0
    reward_sum = 0
    while random_episodes < 10:
        env.render()
        observation, reward, done, _ = env.step(np.random.randint(0,2))
        reward_sum += reward
        if done:
            random_episodes += 1
            print("Reward for this episode was:",reward_sum)
            reward_sum = 0
            env.reset()
        
    # hyperparameters
    H = 50 # number of hidden layer neurons
    batch_size = 25 # every how many episodes to do a param update?
    learning_rate = 1e-1 # feel free to play with this to train faster or more stably.
    gamma = 0.99 # discount factor for reward
    D = 4 # input dimensionality        
    tf.reset_default_graph()
    #This defines the network as it goes from taking an observation of the environment to 
    #giving a probability of chosing to the action of moving left or right.
    observations = tf.placeholder(tf.float32, [None,D] , name="input_x")
    W1 = tf.get_variable("W1", shape=[D, H],
           initializer=tf.contrib.layers.xavier_initializer())
    layer1 = tf.nn.relu(tf.matmul(observations,W1))
    W2 = tf.get_variable("W2", shape=[H, 1],
               initializer=tf.contrib.layers.xavier_initializer())
    score = tf.matmul(layer1,W2)
    probability = tf.nn.sigmoid(score)
    #From here we define the parts of the network needed for learning a good policy.
    tvars = tf.trainable_variables()
    input_y = tf.placeholder(tf.float32,[None,1], name="input_y")
    advantages = tf.placeholder(tf.float32,name="reward_signal")
    # The loss function. This sends the weights in the direction of making actions 
    # that gave good advantage (reward over time) more likely, and actions that didn‘t less likely.
    loglik = tf.log(input_y*(input_y - probability) + (1 - input_y)*(input_y + probability))
    loss = -tf.reduce_mean(loglik * advantages) 
    newGrads = tf.gradients(loss,tvars)
    # Once we have collected a series of gradients from multiple episodes, we apply them.
    # We don‘t just apply gradeients after every episode in order to account for noise in the reward signal.
    adam = tf.train.AdamOptimizer(learning_rate=learning_rate) # Our optimizer
    W1Grad = tf.placeholder(tf.float32,name="batch_grad1") # Placeholders to send the final gradients through when we update.
    W2Grad = tf.placeholder(tf.float32,name="batch_grad2")
    batchGrad = [W1Grad,W2Grad]
    updateGrads = adam.apply_gradients(zip(batchGrad,tvars))
    def discount_rewards(r):
        """ take 1D float array of rewards and compute discounted reward """
        discounted_r = np.zeros_like(r)
        running_add = 0
        for t in reversed(range(r.size)):
            running_add = running_add * gamma + r[t]
            discounted_r[t] = running_add
        return discounted_r
    
    xs,ys,drs = [],[],[]
    #running_reward = None
    reward_sum = 0
    episode_number = 1
    total_episodes = 10000
    init = tf.global_variables_initializer()
    # Launch the graph
    with tf.Session() as sess:
        rendering = False
        sess.run(init)
        observation = env.reset() # Obtain an initial observation of the environment
        # Reset the gradient placeholder. We will collect gradients in 
        # gradBuffer until we are ready to update our policy network. 
        gradBuffer = sess.run(tvars)
        for ix,grad in enumerate(gradBuffer):
            gradBuffer[ix] = grad * 0
    
        while episode_number <= total_episodes:
        
            # Rendering the environment slows things down, 
            # so let‘s only look at it once our agent is doing a good job.
            if reward_sum/batch_size > 100 or rendering == True : 
                env.render()
                rendering = True
            
            # Make sure the observation is in a shape the network can handle.
            x = np.reshape(observation,[1,D])
        
            # Run the policy network and get an action to take. 
            tfprob = sess.run(probability,feed_dict={observations: x})
            action = 1 if np.random.uniform() < tfprob else 0
        
            xs.append(x) # observation
            y = 1 if action == 0 else 0 # a "fake label"
            ys.append(y)
            # step the environment and get new measurements
            observation, reward, done, info = env.step(action)
            reward_sum += reward
            drs.append(reward) # record reward (has to be done after we call step() to get reward for previous action)
            if done: 
                episode_number += 1
                # stack together all inputs, hidden states, action gradients, and rewards for this episode
                epx = np.vstack(xs)
                epy = np.vstack(ys)
                epr = np.vstack(drs)
                xs,ys,drs = [],[],[] # reset array memory
                # compute the discounted reward backwards through time
                discounted_epr = discount_rewards(epr)
                # size the rewards to be unit normal (helps control the gradient estimator variance)
                discounted_epr -= np.mean(discounted_epr)
                discounted_epr /= np.std(discounted_epr)
            
                # Get the gradient for this episode, and save it in the gradBuffer
                tGrad = sess.run(newGrads,feed_dict={observations: epx, input_y: epy, advantages: discounted_epr})
                for ix,grad in enumerate(tGrad):
                    gradBuffer[ix] += grad
                
                # If we have completed enough episodes, then update the policy network with our gradients.
                if episode_number % batch_size == 0: 
                    sess.run(updateGrads,feed_dict={W1Grad: gradBuffer[0],W2Grad:gradBuffer[1]})
                    for ix,grad in enumerate(gradBuffer):
                        gradBuffer[ix] = grad * 0
                
                    # Give a summary of how well our network is doing for each batch of episodes.
                    #running_reward = reward_sum if running_reward is None else running_reward * 0.99 + reward_sum * 0.01
                    print(Average reward for episode %d : %f. % (episode_number,reward_sum/batch_size))
                
                    if reward_sum/batch_size > 200: 
                        print("Task solved in",episode_number,episodes!)
                        break
                    
                    reward_sum = 0
            
                observation = env.reset()

 

参考资料:
《TensorFlow实战》

欢迎付费咨询(150元每小时),我的微信:qingxingfengzi

学习笔记TF037:实现强化学习策略网络