強化學習之CartPole

Dark1nt發表於2021-06-14

0x00 任務

  通過強化學習演算法完成倒立擺任務,控制倒立擺在一定範圍內擺動。

0x01 設定jupyter登入密碼

jupyter notebook --generate-config

jupyter notebook password (會輸入兩次密碼,用來驗證)

jupyter notebook 登入

0x02 建立python note

0x03 程式碼

# 宣告包
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import gym

# 宣告繪圖功能
from JSAnimation.IPython_display import display_animation
from matplotlib import animation
from IPython.display import display
def display_frames_as_gif(frames):
    plt.figure(figsize=(frames[0].shape[1]/72.0,frames[0].shape[0]/72.0),dpi=72)
    patch=plt.imshow(frames[0])
    plt.axis("off")
    
    def animate(i):
        patch.set_data(frames[i])
    anim=animation.FuncAnimation(plt.gcf(),animate,frames=len(frames),interval=50)
    anim.save('move_carpole.mp4') # 儲存動畫
    display(display_animation(anim,default_mode='loop'))

# 隨機移動CartPole
frames=[]
env=gym.make('CartPole-v0')
observation=env.reset() # 重置環境
for step in range(0,200):
    frames.append(env.render(mode='rgb_array')) # 載入各個時刻影像到幀
    action=np.random.choice(2) # 隨機返回: 0 小車向左,1 小車向右
    gym.logger.set_level(40)
    observation,reward,done,info=env.step(action) # 執行動作

執行後

移動 Caprpole的程式碼並不重要,重要的是最後一行observation,reward,done,info=env.step(action)
reward 是 即時獎勵,若執行了action後,小車位置在+-2.4範圍之內而且杆的傾斜成都沒有超過20.9°,則設定獎勵為1.相反,若小車移出+-2.4範圍或者杆傾斜超過了20.9°的話,則獎勵為0。退出時 done是一個變數。若為結束狀態 則為true
這裡程式碼忽略了done, info變數儲存除錯資訊。

最後使用display_frames_as_gif(frames) 函式去儲存我們的gif

# 儲存並繪製視訊
display_frames_as_gif(frames)

可正常儲存視訊

CartPole的狀態

之前討論的迷宮問題中,狀態指的是每個格子的編號,由單個變數表示,0~8,然而倒立擺具有更復雜的狀態定義。

CartPole的狀態儲存在observation中,變數observarion是4個變數組成的列表,每個變數的內容如
小車位置 -2.4~2.4
小車速度 -∞~+∞
杆的角度 -41.8°~+41.8°
杆的角速度 -∞~+∞

因為變數是連續值,如果想要通過表格的形式來表達Q函式,就需要將他們進行離散化
比如使用0~5來標記變數的連續值
-2.4~-1.6=0
-1.6~-0.8=1
依次類推
則總共有6的4次方總組合 1296種型別 數字 表示 CartPole的狀態
而這個時候小車的方向只有向左和向右
所以,可以用1296行x2列的表格來表示Q函式

演算法實現

  • 變數設定
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import gym
# 變數設定
ENV='CartPole-v0' # 設定任務名
NUM_DIZITIZED=6 # 設定離散值個數
# 嘗試執行 CartPole
env=gym.make(ENV) # 設定要執行的任務
observarion=env.reset() # 環境初始化
  • 求取用於離散化的闕值
# 求取用於離散化的闕值
def bins(clip_min,clip_max,num):
    return np.linespace(clip_min,clip_max,num+1)[1:-1] # 返回[-1.6,-0.8,0,0,0.8,1.6]
    

-∞~-1.6=0 -1.6~0.8=1
依次類推

  • 建立函式 根據獲得的闕值對連續變數進行離散化
def digitize_state(observation):
    cart_pos,cart_v,pole_angle,pole_v=observation
    digitized=[
        np.digitize(cart_pos,bins=bins(-2.4,2.4,NUM_DIZITIZED)),
        np.digitize(cart_v,bins=bins(-3.0,3.0,NUM_DIZITIZED)),
        np.digitize(pole_angle,bins=bins(-0.5,0.5,NUM_DIZITIZED)),
        np.digitize(pole_v,bins=bins(-2.0,2.0,NUM_DIZITIZED))
    ]
    return sum([x*(NUM_DIZITIZED)**i) for i,x in enumerate(digitized)])

以6進位制進行計算 如果 存在一個離散值(1,2,3,4) 則求得當前狀態值為 160+2*61+362+4*63=985

  • Q學習實現

這裡需要定義實現類,主要有三個類 Agent Brain 和 Environmet

Agent類表示小推車物件,主要有2個函式,更新Q函式,和確定下一步動作函式
Agent中有一個Brain類的物件作為成員變數。

Brain類可認為是Agent的大腦,通過Q表來實現Q學習,主要有4個函式 bin digitize_state 用來離散化Agent觀察到的observation
函式update_Q_table來更新Q表
函式decision_action 來確定來自Q表的動作。
為什麼需要將Agent和Brain類分開》? 因為如果使用深度強化學習,將表格型Q改成深度強化學習時只需要改變Brain類就行了。

Environment類是OpenAI Gym的執行環境,執行CartPole環境的是run函式

  • start

首先我們需要決定要執行的值動作,所以 Agent將當前狀態 observation_t傳給Brain ,Brain 離散化狀態再根據Q表來確定動作,並將確定的動作返回給Agent,
之後是動作的實際執行環境步驟,Agent將動作action_t傳遞給Environment,Environment執行動作action_t並將執行後的狀態observation_t+1和即時獎勵 reward+1 返回給Agent
再更新Q 表, Agent將當前狀態observation_t 執行動作 action_t 和執行動作後的observation_t+1 即時獎勵reward_t+1傳回給Brain,Brain更新Q表,這4個變數綜合起來被稱為transition
之後 重複該過程就行了,因為獲得最大價值的方式只有一種,所以通過Q學習不斷擬合,最後會形成唯一解。

0x04 強化學習之Q學習的原理(重點!)-》瞬間開悟

  觀察程式碼 self.q_table[state,action]=self.q_table[state,action]+ETA(reward+GAMMAMax_Q_next-self.q_table[state,action]) ,剛開始看時,一臉懵逼,直到想通了某個點。
首先我們需要清楚在大量的資料面前,能夠滿足我們想要的最好的策略 只有一條,有些時候我們可以自己求得該策略,比如迷宮問題,我們可以輕鬆做到,這裡的倒立擺問題我們也能輕鬆做到,但是小球消方塊呢? 我們人類幾乎不能在很短時間做出判斷,然後消除掉所有的方塊,但是機器能。為什麼?

滿足最優策略只有一條,大資料訓練只是為了讓我們的策略最終擬合成為最優策略

還是拿這段程式碼來說 self.q_table[state,action]=self.q_table[state,action]+ETA(reward+GAMMAMax_Q_next-self.q_table[state,action]) Q表的更新是當前Q表+變化值。
所以Q表的更新量其實就是 ETA*(reward+GAMMA*Max_Q_next-self.q_table[state,action])
ETA是學習率。 reward是獎勵,這裡可以認為是0, GAMMA是時間折扣率為0.99 接近為1 self.q_table[state,action] 為當前Q表,記錄了當前狀態和當前的方向。
當我們設定變化值為很小時,最終實現Q表幾乎不變,此時Q表代表了我們的最優策略。 但是為什麼,為什麼它就能擬合到最優,而不是別的?每次擬合的過程是什麼?

抽象概念
我們可以假設有1000多個大的游泳池,我們設定的闕值範圍用游泳圈來表示,水的體積來表示資料範圍,策略可用來表示水體積的變化。第一個游泳池我們隨機生成,游泳池裡灌滿了水,游泳圈的數量固定,當我們的智慧體根據當前策略進行了運動,而我們定義的策略是如果到達我們的目標則獲得獎勵,抽象到游泳池可以認為是,我們從第一個游泳池跳到第二個游泳池的游泳圈範圍裡。當我們這樣做後會得到獎勵,因為獎勵的存在,使得我們不斷往游泳圈跳來獲得最大價值,在一,二,三的泳池中,

相關文章