相較神經網路是"算出"答案
q_learing比較像是在查表
利用回傳狀態的值來當作index(如果是連續的數值要做離散化)呼叫Q learning表格的數值
對應的數值是做某個action可能會拿到的reward
可想而知,某個狀態對應的Q form有最大可能reward的動作
將會是我們接下來會做的動作
Q_form = np.zeros((n, m, n, m) + (4,))
"""
前四個就是回傳的狀態對應的維度
最後一個代表有4種動作
"""
Q_form上個狀態執行某個action的可能reward值將會等於 (1 - learning rate) * 原本的值 + learing rate * (reward + 常數 * 執行action後的狀態可能拿到的最大reward)
Q_form[old_state + (action,)] = (1 - lr) * Q_form[old_state + (action,)] + \
lr * (reward + gamma * np.max(Q_form[new_state]))
"""
lr是learning rate
action是剛執行的動作
old_state是導出action這個動作的狀態
new_state是執行action之後的狀態
reward就...reward
gamma是discount factor,代表要對未來可能獲得的reward之重視程度
"""
- 用m和n決定遊戲場地的大小
- 'P'是player
- 'G'是goal
- '_'是空地
- 移動P到G來得分
from self_do_pygame import game
n = 4
m = 4
new_game = game(n, m)
new_game.show_game()
py, px, gy, gx = new_game.observation())
"""
py是player的縱座標值
px是player的橫座標值
gy是goal的縱座標值
gx是goal的橫座標值
"""
reward, observation, done = new_game.player_move(action)
"""
action的值可以是0, 1, 2, 3
分別對應上下左右
new_game.player_move會回傳三個資訊
reward -> 40 - abs(px - gx) - abs(py - gy)
observation -> 同new_game.observation()
done -> player的座標是否和goal重疊(是否得分)
"""
- 直接使用observation的四個值來呼叫Q_learning的表格
- 一開始先四個方向隨機亂走,之後再使用Q_learning表格的數值
- 然後我train了500000次
剛開始隨機亂走比較多,但因為場地只有4x4,player勉強能走到goal
依照表格做事,結果經常找不到goal
慢慢能找到通往目標的路
基本上都能找到通往目標的路,之後到5e6都是在慢慢優化
基本上都能在個位數個步驟走完,因為場地只有4x4
但有時候會繞路
再多訓練久一點,或許真的能訓練出能一直找出最佳解的模型,但那太久了
而且場地再大一點,訓練所需的epoch數量只會更大
直接使用4個狀態的方法不夠有效率
雖然我用Q learning來解這個遊戲
但這遊戲顯而易見的有個很簡單的最佳解腳本
def action_choice(state):
py, px, gy, gx = state
if (py != gy):
if (gy - py < 0):
return 0
else:
return 1
elif (px != gx):
if (gx - px < 0):
return 2
else:
return 3
我延長了參考腳本的時間
到了幾乎由Q_form全權決定行動的50000過後
找到的路徑步數也都壓在8以內
似乎很順利地學到最佳解做法
我有試過20x20的地圖,訓練過程完全參考腳本
經過5e6個epoch之後,模型也能學到最佳解
看來有個腳本來學習是最有效率的
事實上,在其他的強化學習應用中,一開始先參考純貪心法的腳本似乎也蠻常見的(by chatGPT)
只是當有個腳本是最佳解的時候
還在訓練模型
根本是多此一舉啊
ipynb連結 前面的Q_form是直接接收player和goal的位置,然而,我們其實只要知道他們相減的數值正負就能判斷該往哪移動
於是我就把Q_表格改成這樣:
Q_form = np.zeros((3, 3) + (4,))
#goal在player上或下或沒差, goal在player左或右或沒差
並對state做轉換
def convert(p, g):
"""
將玩家與目標的距離是正或負或0
轉換成0或1或2
"""
if (g - p > 0):
return 0
elif (g - p < 0):
return 1
else:
return 2
def state_convert(state):
"""
將原本遊戲回報的state
轉成Q_form可用的格式
"""
py, px, gy, gx = state
return (convert(py, gy), convert(px, gx))
回到與最初的狀態一樣,是先隨機亂走,原本也跟之前一樣epoch=5e5,但在把與腳本最佳解的步數差距圖像化之後,發現我其實訓練到20000他們的差距幾乎都是0了(現在才想起來我可以把它圖像化)
後半部偶爾會出現非最佳解,應該是剛好隨機到隨機亂走的模式(我沒有讓隨機亂走的機率衰減到0)
他看起來是學到最佳解的方法了
因為這個方法只關心相對位置,所以不管幾乘幾都能找到最佳解