1. 程式人生 > >學習筆記TF037:實現強化學習策略網絡

學習筆記TF037:實現強化學習策略網絡

屬於 控制 返回 獎勵 渲染 動作 ren 虛擬 初始

強化學習(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:實現強化學習策略網絡