1. 程式人生 > >強化學習之四:基於策略的Agents (Policy-based Agents)

強化學習之四:基於策略的Agents (Policy-based Agents)

本文是對Arthur Juliani在Medium平臺釋出的強化學習系列教程的個人中文翻譯,該翻譯是基於個人分享知識的目的進行的,歡迎交流!(This article is my personal translation for the tutorial written and posted by Arthur Juliani on Medium.com. And my work is completely based on aim of sharing knowledges and welcome communicating!)

純屬自願翻譯,只為學習與分享知識。所以如果本系列教程對你有幫助,麻煩不吝在

github的專案上點個star吧!非常感謝!


在休息了一週後,我又帶著我的強化學習系列教程的part 2回來了!在part 1,我已經展示瞭如何組裝一個agent可以學會去在兩種可能的選擇中回報更多的那個。在本篇博文中,我將準備描述我們如何從之前那個簡單的agent出發,讓它進一步學會吸收從環境中獲得的觀察(Observation),並採取可以讓它獲得長期最優回報的行動,而不僅僅是當下回報最優的行動。意即,我們將獲得一個完備的agent。

將完整問題暴露給一個agent的環境(Environments)一般稱作馬爾科夫決策過程(Markov Decision Processes (MDPs))

。這些環境不只提供給定行動的回報和狀態遷移,而且這些回報也是基於(condition on)環境的狀態(state)以及agent在那個狀態下所採取的行動的。這些動態(dynamics)也是暫時(temporal)的,並且也會在時間上有所延遲。

說得更正式一點,我們可以像這樣定義馬爾科夫決策過程:一個MDP有一個所有可能的狀態集合S,我們的agent隨時隨刻都處在集合中的某個狀態s。還有一個所有可能的行動集合A,我們的agent隨時隨刻都將從中選擇一個行動來執行。給定一個狀態行動對(s,a),轉移到新狀態s’的概率由T(s,a)定義,而回報r由R(s,a)定義。如此,在一個MDP的任意時刻,一個agent都在一個狀態s中,採取了行動a,併到達新狀態s‘同時獲得回報r。

雖然聽起來相對比較簡單,但是我們可以把幾乎任何任務都考慮成一個MDP架構。比如,想象開啟一個門,狀態就是我們視覺中的門,以及我們身體的位置還有真實世界的門物件。行動集合是任意時刻我們身體可以採取的行動。而回報則是門可以被成功地開啟。某些行動,像走向門這個行為是為了解決這個問題而比較必要的,但是它們本身沒有回報,因為只有開啟門本身才能提供回報。在這種情況下,一個agent需要學習分配值(value)到各個最終可以導向回報的行為,這也就導向了我們對**時序動態性(temporal dynamics)**的介紹。

Cart-Pole任務(Cart-Pole Task)

為了完成這個任務,我們將需要一個比雙臂賭博機更復雜的挑戰給agent。為了滿足這個需求,我們將用到OpenAI的gym,它是一系列強化學習環境的集合。我們將使用其中最經典的任務之一,Cart-Pole。想了解更多有關OpenAI的gym的內容,以及這個具體任務相關的知識,可以看一下它們的教程。本質上,我們將讓我們的agent學習如何儘可能長時間地平衡一個杆子(pole),使其不倒下。不像雙臂賭博機,這個任務要求:

  • 觀察-agent需要知道杆子當前在哪,以及它現在的角度如何。為了實現這一點,我們的神經網路需要獲得觀察,並在生成採取各種行動的相應概率時參考觀察的情況。
  • 延遲迴報-讓杆子儘可能地保持不倒下意味著要一直移動杆子,使得它在現在和未來都儘量不倒下。為了實現這一點,我們將調整每個觀察-行動對的回報,這需要用到一個給行動賦權的函式(using a function that weighs actions over time)。

為了將各個時間的回報都考慮進來,我們之前的教程裡用到的策略梯度將需要做一點調整。第一個調整是,我們現在需要用超過一回一次的經驗來更新agent。為了實現這一點,我們將把經驗都收集在一個快取中,並偶爾地將它們一次性地更新到agent上。這些經驗的序列有時候稱為“首次展示”(rollouts),或者叫“經驗痕跡”(experience trace)。然而我們不能只是用這些rollouts本身,我們將需要保證回報是由折現因子進行了恰當地調整的。

直覺上,這使得每個行動的考慮都不僅包括當下的即時回報,還有所有未來的回報。我們現在用這個稍作修改的回報作為損失方程中的優勢的估計值。做出這些改變後,我們已經準備好來解決CartPole問題了!

我們開始吧!


'''
Simple Reinforcement Learning in Tensorflow Part 2-b:
Vanilla Policy Gradient Agent
This tutorial contains a simple example of how to build a policy-gradient based agent that can solve the CartPole problem. For more information, see this Medium post. This implementation is generalizable to more than two actions.

For more Reinforcement Learning algorithms, including DQN and Model-based learning in Tensorflow, see my Github repo, DeepRL-Agents.
'''

import tensorflow as tf
import tensorflow.contrib.slim as slim
import numpy as np
import gym
import matplotlib.pyplot as plt
%matplotlib inline

try:
    xrange = xrange
except:
    xrange = range

    
    
env = gym.make('CartPole-v0')

# Making new env: CartPole-v0
The Policy-Based Agent



gamma = 0.99

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(xrange(0, r.size)):
        running_add = running_add * gamma + r[t]
        discounted_r[t] = running_add
    return discounted_r



class agent():
    def __init__(self, lr, s_size,a_size,h_size):
        #These lines established the feed-forward part of the network. The agent takes a state and produces an action.
        self.state_in= tf.placeholder(shape=[None,s_size],dtype=tf.float32)
        hidden = slim.fully_connected(self.state_in,h_size,biases_initializer=None,activation_fn=tf.nn.relu)
        self.output = slim.fully_connected(hidden,a_size,activation_fn=tf.nn.softmax,biases_initializer=None)
        self.chosen_action = tf.argmax(self.output,1)

        #The next six lines establish the training proceedure. We feed the reward and chosen action into the network
        #to compute the loss, and use it to update the network.
        self.reward_holder = tf.placeholder(shape=[None],dtype=tf.float32)
        self.action_holder = tf.placeholder(shape=[None],dtype=tf.int32)
        
        self.indexes = tf.range(0, tf.shape(self.output)[0]) * tf.shape(self.output)[1] + self.action_holder
        self.responsible_outputs = tf.gather(tf.reshape(self.output, [-1]), self.indexes)

        self.loss = -tf.reduce_mean(tf.log(self.responsible_outputs)*self.reward_holder)
        
        tvars = tf.trainable_variables()
        self.gradient_holders = []
        for idx,var in enumerate(tvars):
            placeholder = tf.placeholder(tf.float32,name=str(idx)+'_holder')
            self.gradient_holders.append(placeholder)
        
        self.gradients = tf.gradients(self.loss,tvars)
        
        optimizer = tf.train.AdamOptimizer(learning_rate=lr)
        self.update_batch = optimizer.apply_gradients(zip(self.gradient_holders,tvars))
        
        
# Training the Agent

tf.reset_default_graph() #Clear the Tensorflow graph.

myAgent = agent(lr=1e-2,s_size=4,a_size=2,h_size=8) #Load the agent.

total_episodes = 5000 #Set total number of episodes to train agent on.
max_ep = 999
update_frequency = 5

init = tf.global_variables_initializer()

# Launch the tensorflow graph
with tf.Session() as sess:
    sess.run(init)
    i = 0
    total_reward = []
    total_lenght = []
        
    gradBuffer = sess.run(tf.trainable_variables())
    for ix,grad in enumerate(gradBuffer):
        gradBuffer[ix] = grad * 0
        
    while i < total_episodes:
        s = env.reset()
        running_reward = 0
        ep_history = []
        for j in range(max_ep):
            #Probabilistically pick an action given our network outputs.
            a_dist = sess.run(myAgent.output,feed_dict={myAgent.state_in:[s]})
            a = np.random.choice(a_dist[0],p=a_dist[0])
            a = np.argmax(a_dist == a)

            s1,r,d,_ = env.step(a) #Get our reward for taking an action given a bandit.
            ep_history.append([s,a,r,s1])
            s = s1
            running_reward += r
            if d == True:
                #Update the network.
                ep_history = np.array(ep_history)
                ep_history[:,2] = discount_rewards(ep_history[:,2])
                feed_dict={myAgent.reward_holder:ep_history[:,2],
                        myAgent.action_holder:ep_history[:,1],myAgent.state_in:np.vstack(ep_history[:,0])}
                grads = sess.run(myAgent.gradients, feed_dict=feed_dict)
                for idx,grad in enumerate(grads):
                    gradBuffer[idx] += grad

                if i % update_frequency == 0 and i != 0:
                    feed_dict= dictionary = dict(zip(myAgent.gradient_holders, gradBuffer))
                    _ = sess.run(myAgent.update_batch, feed_dict=feed_dict)
                    for ix,grad in enumerate(gradBuffer):
                        gradBuffer[ix] = grad * 0
                
                total_reward.append(running_reward)
                total_lenght.append(j)
                break

        
            #Update our running tally of scores.
        if i % 100 == 0:
            print(np.mean(total_reward[-100:]))
        i += 1

'''
16.0
21.47
25.57
38.03
43.59
53.05
67.38
90.44
120.19
131.75
162.65
156.48
168.18
181.43
'''

現在,我們已經有了一個功能齊全的強化學習agent了。不過我們的agent還遠沒有達到最先進的水平。當我們在用神經網路來表示策略時,這個網路還不像大多數比較先進的網路那麼深或複雜。在下一篇部落格裡,我將展示如何用深度神經網路來創造可以學習複雜環境,並且可以玩比平衡杆更有意思的遊戲的agent。用這樣的方法,我們將接觸到可以用一個網路從複雜環境中學到的那類表徵(representations)。

如果這篇博文對你有幫助,你可以考慮捐贈以支援未來更多的相關的教程、文章和實現。對任意的幫助與貢獻都表示非常感激!

如果你想跟進我在深度學習、人工智慧、感知科學方面的工作,可以在Medium上follow我 @Arthur Juliani,或者推特@awjliani。

用Tensorflow實現簡單強化學習的系列教程: