一、迷宮游戲
1.環境已知
迷宮環境是定義好的,障礙物位置和空位置是已知的;
# 定義迷宮
grid = [[0, 0, 0, 1, 0],[0, 1, 0, 1, 0],[0, 1, 0, 0, 0],[0, 0, 0, 1, 0],[0, 1, 1, 1, 0]
]
2.獎勵方式已知
如果碰到障礙物則得-1,如果到終點則得10分,正常走一步-0.1分。
# 檢查是否越界或碰到障礙if 0 <= row < self.rows and 0 <= col < self.cols and self.grid[row][col] == 0:# 滿足在邊界內部,且網格為空(對應數值為0)self.state = (row, col) #可以走到這個位置else:return self.state, -1, False # 碰到障礙或越界,返回懲罰-1,標記未完成# 檢查是否到達終點if self.state == self.goal:return self.state, 10, True # 到達終點,返回獎勵10,標記完成else:return self.state, -0.1, False # 正常移動,返回小懲罰-0.1,標記未完成
3.動作選擇策略
ε-greedy策略選擇動作。
def choose_action(self, state):# 根據ε-greedy策略選擇動作,以epsilon的概率選擇探索,以1-epsilon的概率選擇利用# 一般隨著時間的推移,epsilon逐漸減小,即減小探索,增大利用概率# 如果隨機抽樣小于epsilon,則選擇探索,即隨機抽取動作if random.uniform(0, 1) < self.epsilon: return random.choice([0, 1, 2, 3]) # 探索# 如果隨機抽樣大于等于epsilon,則選擇利用,即利用現有規則進行動作選擇else:return np.argmax(self.q_table[state]) # 利用,state是當前狀態,為二維坐標
4.Q值更新方法
# Q值更新參數方法 q(st,at)=q(st,at)+alpha*(reward+gamma*max(q)-q(st,at))self.q_table[state][action] += self.alpha * (reward + self.gamma * best_next_q - self.q_table[state][action])state = next_state # 狀態更新
5.Qlearning計算流程圖
二、代碼實現
import numpy as np
import random# 定義迷宮環境
class Maze:def __init__(self, grid, start, goal):self.grid = grid # 迷宮網格,0表示空地,1表示障礙self.start = start # 起點self.goal = goal # 終點self.rows, self.cols = len(grid), len(grid[0]) # 網格行、列邊界self.state = start # 當前狀態def reset(self):# 重置迷宮狀態self.state = self.startreturn self.statedef step(self, action):# 根據動作移動智能體row, col = self.stateif action == 0: # 上row -= 1 # 行減1elif action == 1: # 下row += 1 # 行加1elif action == 2: # 左col -= 1 # 列-1elif action == 3: # 右col += 1 # 列+1# 檢查是否越界或碰到障礙if 0 <= row < self.rows and 0 <= col < self.cols and self.grid[row][col] == 0:# 滿足在邊界內部,且網格為空(對應數值為0)self.state = (row, col) #可以走到這個位置else:return self.state, -1, False # 碰到障礙或越界,返回懲罰-1,標記未完成# 檢查是否到達終點if self.state == self.goal:return self.state, 10, True # 到達終點,返回獎勵10,標記完成else:return self.state, -0.1, False # 正常移動,返回小懲罰-0.1,標記未完成def render(self):# 可視化迷宮for r in range(self.rows): # 遍歷狀態for c in range(self.cols): # 遍歷動作if (r, c) == self.state: # 對于當前位置,用字母A表示print("A", end=" ") # 智能體位置elif (r, c) == self.goal: #對于目標位置用字母G表示print("G", end=" ") # 終點elif self.grid[r][c] == 1: # 對于障礙物用#表示print("#", end=" ") # 障礙else: # 對于空地用0表示print("0", end=" ") # 空地print()print()# Q-learning算法
class QLearning:def __init__(self, maze, alpha=0.1, gamma=0.99, epsilon=0.1):self.maze = maze # 迷宮環境self.alpha = alpha # 學習率self.gamma = gamma # 折扣因子self.epsilon = epsilon # 探索概率self.q_table = np.zeros((maze.rows, maze.cols, 4)) # Q表,4個動作,三個維度def choose_action(self, state):# 根據ε-greedy策略選擇動作,以epsilon的概率選擇探索,以1-epsilon的概率選擇利用# 一般隨著時間的推移,epsilon逐漸減小,即減小探索,增大利用概率# 如果隨機抽樣小于epsilon,則選擇探索,即隨機抽取動作if random.uniform(0, 1) < self.epsilon: return random.choice([0, 1, 2, 3]) # 探索# 如果隨機抽樣大于等于epsilon,則選擇利用,即利用現有規則進行動作選擇else:return np.argmax(self.q_table[state]) # 利用,state是當前狀態,為二維坐標def train(self, episodes):# 訓練for episode in range(episodes):state = self.maze.reset() # 重置狀態done = False # 訓練完成標志total_reward = 0 # 總獎勵while not done:action = self.choose_action(state) # 選擇動作,根據1-epsilon策略next_state, reward, done = self.maze.step(action) #根據動作移動智能體total_reward += reward# Q-learning更新規則best_next_q = np.max(self.q_table[next_state]) # Qtable里面下一狀態對應Q的最大值# Q值更新參數方法 q(st,at)=q(st,at)+alpha*(reward+gamma*max(q)-q(st,at))self.q_table[state][action] += self.alpha * (reward + self.gamma * best_next_q - self.q_table[state][action])state = next_state # 狀態更新 # 每當完成100回合,則輸出一次總獎勵數據if (episode + 1) % 100 == 0:print(f"Episode {episode + 1}: Total Reward = {total_reward}")def test(self):# 測試訓練后的策略state = self.maze.reset()done = Falsesteps = []while not done:action = np.argmax(self.q_table[state]) #選擇Q表中最大的動作next_state, _, done = self.maze.step(action) steps.append(action)state = next_stateself.maze.render() # 可視化迷宮print("Steps taken:", steps) #輸出動作集合,每一步動作都被儲存倒steps【】列表中# 定義迷宮
grid = [[0, 0, 0, 1, 0],[0, 1, 0, 1, 0],[0, 1, 0, 0, 0],[0, 0, 0, 1, 0],[0, 1, 1, 1, 0]
]
start = (0, 0) # 起點
goal = (4, 4) # 終點# 創建迷宮和Q-learning對象
maze = Maze(grid, start, goal)
ql = QLearning(maze)# 訓練和測試
ql.train(episodes=1000) #訓練1000輪
ql.test() #測試