基于Policy Gradient实现CartPole
http://chenrudan.github.io/blog/2016/09/04/cartpole.html
基于Policy Gradient實現CartPole
8月的時候把David silver的強化學習課上了,但是一直對其中概念如何映射到現實問題中不理解,半個月前突然發現OpenAI提供了一個python庫Gym,它創造了強化學習的environment,可以很方便的啟動一個強化學習任務來自己實現算法,并且提供了不少可以解決的問題來練手。本文針對如何解決入門問題CartPole,來解釋一下怎么將之前課上的算法轉化成實現代碼。【轉載請注明出處】chenrudan.github.io
8月的時候把David silver的強化學習課上了,但是一直對其中概念如何映射到現實問題中不理解,半個月前突然發現OpenAI提供了一個python庫Gym,它創造了強化學習的environment,可以很方便的啟動一個強化學習任務來自己實現算法(新智元OpenAI簡介[1]),并且提供了不少可以解決的問題來練手https://openai.com/requests-for-research/。本文針對如何解決入門問題CartPole,來解釋一下怎么將之前課上的算法轉化成實現代碼。這里強烈推薦一下官網的教程http://kvfrans.com/simple-algoritms-for-solving-cartpole/,因為這個作者只是個高中生T^T…
建了一個強化學習討論qq群,有興趣的可以加一下群號595176373或者掃描下面的二維碼。
1. Gym庫
它提供了一些函數接口,模擬了強化學習問題中environment,當向它傳遞一個動作,它相應會返回執行這個動作后的狀態、獎賞等。
| 1 2 3 4 | #啟動某種環境 env = gym.make('CartPole-v0') #針對傳進來的動作返回狀態observation等 observation, reward, done, info = env.step(action) |
執行pip install gym即可安裝,https://gym.openai.com/docs中有實例,復制代碼運行即可檢查是否安裝成功。此外提供了env.monitor來記錄下算法執行過程,它會保存為.mp4文件,然后上傳到OpenAI網站上可以檢查執行效率,上傳可以通過執行代碼中加入api_key(鑒別用戶),我是直接把api_key寫入了~/.bashrc文件中即”export OPENAI_GYM_API_KEY=”。
2. CartPole問題
CartPole的玩法如下動圖所示,目標就是保持一根桿一直豎直朝上,桿由于重力原因會一直傾斜,當桿傾斜到一定程度就會倒下,此時需要朝左或者右移動桿保證它不會倒下來。我們執行一個動作,動作取值為0或1,代表向左或向右移動,返回的observation是一個四維向量,reward值一直是1,當桿倒下時done的取值為False,其他為True,info是調試信息打印為空具體使用暫時不清楚。如果桿豎直向上的時間越長,得到reward的次數就越多。
| 1 2 3 4 | #從動作空間中采樣一個動作 action = env.action_space.sample() observation, reward, done, info = env.step(action) print observation |
結果是[-0.061586 -0.75893141 0.05793238 1.15547541]。
圖1 CartPole示意圖3. 三種解法
目的是在不同狀態下執行出合適的action,代碼中要做的就是替換掉采樣這一行,用policy來決定執行什么動作。也就是說此處需要決定policy的形式,官網給出了兩種思路,已知policy的輸入是當前所處的狀態observation,輸出是action的取值即0 or 1,observation是一個四維向量,如果對這個向量求它的加權和,就可以得到一個值,那么就可以根據加權和的符號來決定action,同樣可以用sigmoid函數當成二分類問題。基于這兩種policy可以得到下面三種解法,核心就在于通過改變加權的權重值就能改變policy。
3.1 Random Guessing Algorithm & Hill Climbing Algorithm
由于policy中權重也是一個四維向量,如果隨機給四維向量賦值,有機會得到比較好的policy。首先先實現一個函數用來衡量給定的某組權重效果如何,函數返回值是這組權重下得到的獎賞,意義是桿維持了多長時間未倒下,代碼如下。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | def evaluate_given_parameter_by_sign(env, weight): #啟動初始狀態 observation = env.reset() #這組參數返回的總reward total_reward = 0. for t in range(1000): #這個渲染函數就是實時展示圖1,如果隱藏,代碼正常執行,但是不會顯示圖1了 env.render() weighted_sum = np.dot(weight, observation) #根據符號policy選出action if weighted_sum >= 0: action = 1 else: action = 0 observation, reward, done, info = env.step(action) total_reward += reward if done: break return total_reward |
然后要改變權重,這里試驗了兩種方法,一種是random guess,即隨機給四維權重weight賦值,一種是hill climbing,即給當前最好的權重加上一組隨機值,如果加上這組值持續時間變長了那么就更新最好的權重,如果沒有變的更好就不更新。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | def random_guess(): env = gym.make('CartPole-v0') np.random.seed(10) best_reward = -100.0 for iiter in xrange(1000): #####random guess隨機初始化權重weight#### weight = np.random.rand(4) ##### ####hill climbing給best weight加隨機值 weight = best_weight + np.random.normal(0, 0.01, 4) ##### cur_reward = evaluate_given_parameter_by_sign(env, weight) if cur_reward > best_reward: best_reward = cur_reward best_weight = weight if best_reward == 1000: break print("XXX algorithm best reward", best_reward) print("XXX algorithm best weight", best_weight) |
3.2 Policy Gradient
上面的兩種方法都是在隨機的改變權重,針對這種參數非常少的情況確實能得到不錯的效果,但是一旦參數數目增多,這種方式耗時非常大,一點也不實用。而第七課[2]講解了兩種Policy Gradient的方法,分別是Monte-Carlo Policy Gradient和Actor-Critic Policy Gradient。我們知道衡量policy好壞有三種方法,一是在某個狀態下和該policy作用下能獲得的值函數值,一是該policy作用下能獲得的所有狀態的期望值函數,一是在該policy作用下能獲得的所有狀態的期望immdiate reward,并且推導出了這三種方法的統一導數形式,即衡量policy的目標函數導數為▽θJ(θ)=Eπθ[▽θlogπθ(s,a)Qπθ(s,a)]▽θJ(θ)=Eπθ[▽θlogπθ(s,a)Qπθ(s,a)],這個式子也就是policy gradient。
根據題目的意思,此處的policy換成邏輯回歸,即πθ(s,a)=11+e?wxπθ(s,a)=11+e?wx那么式子中▽θlogπθ(s,a)=(1?pi)?(?x)▽θlogπθ(s,a)=(1?pi)?(?x)。在第一種方法中用直接用immdiate reward代替Qπθ(s,a)Qπθ(s,a),所以在本例中就是直接取1。
首先定義一下選擇action的函數,也就是利用sigmoid函數進行二分類。
| 1 2 3 4 5 6 7 8 | def choose_action(weight, observation): weighted_sum = np.dot(weight, observation) pi = 1 / (1 + np.exp(-weighted_sum)) if pi > 0.5: action = 1 else: action = 0 return pi, action |
由于Monte-Carlo方法中需要先基于某組參數算出一個episode,再基于這個episode來更新policy的參數,所以需要實現一個函數產生一個episode。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | def generate_episode(env, weight): episode = [] pre_observation = env.reset() t = 0 #generate 1 episodes for training. while 1: #env.render() pi, action = choose_action(weight, pre_observation) observation, reward, done, info = env.step(action) #將這個episode的每一步產生的數據保存下來 episode.append([pre_observation, action, pi, reward]) pre_observation = observation t += 1 if done or t > 1000: break return episode |
從而可以實現第七課中Monte-Carlo的更新方法。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | def monte_carlo_policy_gradient(env): learning_rate = -0.0001 best_reward = -100.0 weight = np.random.rand(4) for iiter in xrange(1000): cur_episode = generate_episode(env, weight) for t in range(len(cur_episode)): observation, action, pi, reward = cur_episode[t] #根據第七課的更新公式 weight += learning_rate*(1-pi)*np.transpose(-observation)*reward #衡量算出來的weight表現如何 cur_reward = evaluate_given_parameter_sigmoid(env, weight) print 'Monte-Carlo policy gradient get reward', cur_reward |
而針對Actor critic的方法,則是把值函數Qπθ(s,a)Qπθ(s,a)也當成observation的含參函數,且直接把observation的加權和當成值函數的取值,那么也就能由第七課的更新公式來同時更新值函數和policy的參數。代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | def actor_critic_policy_gradient(env): gamma = 1 p_weight = np.random.rand(4) #值函數的權重 v_weight = np.random.rand(4) p_learning_rate = -0.0001 v_learning_rate = -0.0001 done = True for iiter in xrange(1000): t = 0 while 1: if done: print 'start new training...' print 'p_weight', p_weight print 'v_weight', v_weight pre_observation = env.reset() pre_pi, pre_action = choose_action(p_weight, pre_observation) pre_phi = pre_observation pre_q = np.dot(v_weight, pre_phi) #env.render() observation, reward, done, info = env.step(pre_action) pi, action = choose_action(p_weight, observation) phi = observation q = np.dot(v_weight, phi) delta = reward + gamma*q - pre_q p_weight += p_learning_rate*(1-pre_pi)*np.transpose(-pre_observation)*pre_q v_weight += v_learning_rate*delta*np.transpose(pre_phi) pre_pi = pi pre_observation = observation pre_q = q pre_phi = phi pre_action = action t += 1 if done: break cur_reward = evaluate_given_parameter_sigmoid(env, p_weight) print 'Actor critic policy gradient get reward', cur_reward |
4.提交到OpenAI
上面的代碼實現以后,就能夠提交到OpenAI的網站上去評估效果如何,首先加上兩行代碼,變成下面的樣子。
| 1 2 3 4 | env = gym.make('CartPole-v0') env.monitor.start('cartpole-hill/', force=True) actor_critic_policy_gradient(env) env.monitor.close() |
這會將訓練過程記錄下來生成.mp4文件,如果像我這樣將api_key寫入~/.bashrc,就可以直接執行下面代碼提交給OpenAI。
| 1 | gym.upload('cartpole-hill') |
最后在網站上就能看到如下的結果。
圖2 結果提交成功圖5.小結
我的policy gradient是完全按照第七課的內容實現的,但是實際上效果還不夠好,并且非常依賴初始值,初始值好就很快收斂,不好就會一直惡性循環。總之感覺這個網站還是很有意思的,值得去玩一玩,文中的代碼在這里。
[1]?【重磅】馬斯克的AI野心——OpenAI Gym系統深度解析
[2]?【David Silver強化學習公開課之七】Policy Gradient
轉載于:https://www.cnblogs.com/jukan/p/7772231.html
總結
以上是生活随笔為你收集整理的基于Policy Gradient实现CartPole的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安逸花借款申请条件
- 下一篇: 过年找工作 比年前要好找的多