強化學習:一個Q_Learning算法+gym自定義可視化環境實例

原文地址

分類目錄——強化學習

  • 先觀察效果
訓練

​ 上圖是訓練過程中的圖片

測試

​ 上圖是訓練結束後測試階段的效果,依次選擇0,1,2,3四個位置,智能體均能自行到達終點

  • 環境解釋

    狀態空間S:共有5個狀態,從左到右一次爲0,1,2,3,4

    動作空間A:共有3個動作,0,1,2分別表示原地不動,向左,向右

    Q值表爲S*A的表格,每個Q值表示在狀態s下選擇動作a的Q值(s跟a搭配的合適程度,越大越合適,回報越高,根據一個收斂的Q值表進行動作選擇可以保證選擇處一條全局收益最高的路線)

    上圖中的環境時我在gym模塊的框架下自行構建的可視化環境,關於gym可視化環境的構建可以參見 分類目錄——強化學習

  • Q_Learning算法部分

    import numpy as np
    import pandas as pd
    import time
    from gymTest.ttenvline import EnvLine
    
    class QLearning:
        def __init__(self, actions_space, target, learning_rate=0.01, reward_decay=0.9, e_greedy=0.9):
            self.actions = actions_space    # 可以選擇的動作空間
            self.target = target            # 目標狀態(終點)
            self.lr = learning_rate         # 學習率
            self.gamma = reward_decay       # 回報衰減率
            self.epsilon = e_greedy         # 探索/利用 貪婪係數
            self.q_table =pd.DataFrame(columns=range(self.actions.n), dtype=np.float64) # Q值表
    
        def choose_action(self, observation):
            self.check_state_exist(observation) # 調用這個函數的作用是檢查Q值表中有無該狀態,如果沒有就向表中追加
            # 選擇動作
            # 假設epsilon=0.9,下面的操作就是有0.9的概率按Q值表選擇最優的,有0.1的概率隨機選擇動作
            # 隨機選動作的意義就是去探索那些可能存在的之前沒有發現但是更好的方案/動作/路徑
            if np.random.uniform() < self.epsilon:
                # 選擇最佳動作(Q值最大的動作)
                state_action = self.q_table.loc[observation, :]
                # 如果幾個動作的Q值同爲最大值,從中選一個
                action = np.random.choice(state_action[state_action == np.max(state_action)].index)
            else:
                # 隨機選擇一個動作
                action = self.actions.sample()
            return action
    
        # 學習,主要是更新Q值
        def learn(self, s, a, r, s_):
            self.check_state_exist(s_)
            q_predict = self.q_table.loc[s, a]
            if s_ != self.target:   # 如果下一個狀態不是終點
                q_target = r + self.gamma * self.q_table.loc[s_, :].max()   # 這就是Q值的迭代更新公式
            else:
                q_target = r        # 下一個狀態不是終點
            self.q_table.loc[s, a] += self.lr * (q_target - q_predict)     # update
    
        # 檢查Q值表中有無狀態state,如果沒有就向表中追加
        def check_state_exist(self, state):
            if state not in self.q_table.index:
                # 向Q表中追加一個狀態
                self.q_table = self.q_table.append(
                    pd.Series(
                        [0]*len(self.q_table.columns),
                        index=self.q_table.columns,
                        name=state
                    )
                )
    
    if __name__ == '__main__':
        env = EnvLine()     # 這就是圖示的畫面環境
        model = QLearning(
            env.action_space,
            env.target,
        )
        # 訓練
        for episode in range(100):
            # 初始化狀態
            observation = env.reset()
            env.render()
    
            while True:
                # 基於當前狀態選擇動作
                action = model.choose_action(observation)
                # 執行動作,獲取回報
                observation_, reward, done = env.step(action)
                # 刷新畫面
                env.render()
                # 學習,更新Q表
                model.learn(observation, action, reward, observation_)
                # 推進狀態(當前狀態前移)
                observation = observation_
                # 如果達到終點,獲得done=True,跳出循環
                if done:
                    break
                time.sleep(0.1)   # 延時可以提供更好的可視化效果,相對的也會減慢訓練
            time.sleep(0.5)
        # 如果訓練順利,此時model中的q_table就已經收斂了
        print(model.q_table)
        #     0            1              2
        # 4   2.063857    - 0.008877      0.100000
        # 3   0.083175    - 0.015520      5.341192
        # 2   - 0.056166  - 0.060211      0.806275
        # 1   - 0.237123  - 0.236387      - 0.235704
        # 0   - 0.372681  - 0.372961      - 0.372209
    
        # 測試
        model.epsilon = 1  # 因爲是測試(應用),講epsilon設置成1,省掉“探索”的過程,直接“利用”
    
        for episode in range(10):
            print('episode', episode, '----------')
            for i in range(env.observation_space.n):
                print(i)
                # 初始化轉態
                observation = env.reset(i)  # 遍歷着在狀態空間裏初始化
                env.render()
                time.sleep(1)
    
                while True:
                    action = model.choose_action(observation)
                    observation_, reward, done = env.step(action)  # 執行動作,獲得下一個狀態,回報
                    env.render()
                    observation = observation_
                    if done:
                        break
                    time.sleep(0.5)
                time.sleep(1)
    
  • 收斂後的Q值表分析

     	#     0            1              2
        # 4   2.063857    - 0.008877      0.100000
        # 3   0.083175    - 0.015520      5.341192
        # 2   - 0.056166  - 0.060211      0.806275
        # 1   - 0.237123  - 0.236387      - 0.235704
        # 0   - 0.372681  - 0.372961      - 0.372209
    

    其中豎向爲狀態,橫向爲動作。

    觀察Q值表的分佈,可以發現,越靠近終點的位置,Q值的差距拉的越大,這是因爲回報衰減gamma存在的原因,終點的較大回報r在經過數輪前項傳遞之後,在開始的0狀態上產生的影響已經很小了,但是還是能區分出最佳動作。

    在狀態0下,動作2(向右)的Q值最大,選擇動作2進入狀態1

    在狀態1下,動作2(向右)的Q值最大,選擇動作2進入狀態3

    . . .

    直到到達終點

  • 全部代碼

  • 參考文獻

    Q-learning 思維決策

    分類目錄——強化學習(更新中)

    什麼是gym

    gym自定義可視化環境繪製

    gym自定義可視化環境實例

    強化學習調用gym環境實例

    從Q_Learning看強化學習

    一個Q_Learning強化學習自定義gym環境可視化實例

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章