1:问题描述
有一个迷宫,小人从迷宫的左上角出发,前往右下角的终点则游戏结束。迷宫中还会有一些障碍物不可以行走,求小人从起点走到终点的最优策略。
2:设置参数
grid为迷宫地图,”S“是起点,”G“是终点,”X“是障碍物。
V是每个状态的状态值函数,初始为 [ [0] *3 for _ in range(3) ]
P是状态转移概率矩阵,P中的每个元素指的是从状态S选择动作a后状态转移成S’的概率,在这个问题中状态的表示是二维的,即用坐标表示状态。
R是奖励矩阵,R中的每个元素指的是从状态S选择动作a获得的奖励。
action_dict是动作的集合。在这个问题中,动作只有上下左右四种。
import numpy as np
# 网格世界的状态矩阵
grid = np.array([
["S", "0", "0"],
["X", "0", "X"],
["0", "0", "G"]
])
# 防止圈走动
# 状态值函数的初始化
V = np.zeros_like(grid, dtype=np.float32)
# 定义状态转移概率矩阵和奖励矩阵
P = np.zeros((3, 3, 4, 3, 3), dtype=np.float32) # (s, a, s')
R = np.zeros((3, 3, 4), dtype=np.float32) # (s, a)
action_dict = {
0: "UP",
1: "DOWN",
2: "LEFT",
3: "RIGHT"
}
3:求参数的值
首先遍历每个状态(也就是遍历每个坐标(i,j)),对于每个状态再遍历所有可能的动作。在不超出地图边界且不走到障碍物的前提下,更新next_i,next_ j,然后为P[i, j, a, next_i, next_j]赋值为1/4。#当然也可以自己设置概率
对于回报矩阵来说,如果智能体走到了终点,则reward=10,若智能体走到了障碍物,则reward=-1 且next_i 和next_ j赋值回i和j,目的就是不允许走到障碍物。若智能体走到了普通状态,奖励也为 -1,目的是防止智能体循环走动。
# 定义状态转移概率矩阵和奖励矩阵的值
for i in range(3):
for j in range(3):
if grid[i, j] == "X":
# 障碍物状态
continue
for a in range(4):
# 针对每个状态和动作,计算可能的下一个状态和对应的概率和奖励
if a == 0: # UP
next_i = max(i - 1, 0)
next_j = j
elif a == 1: # DOWN
next_i = min(i + 1, 2)
next_j = j
elif a == 2: # LEFT
next_i = i
next_j = max(j - 1, 0)
elif a == 3: # RIGHT 把规则写出来
next_i = i
next_j = min(j + 1, 2)
if grid[next_i, next_j] == "X":
# 下一个状态是障碍物状态
next_i = i
next_j = j
r = -1.0
elif grid[next_i, next_j] == "G":
# 下一个状态是终点状态
r = 10.0
else:
# 下一个状态是普通状态
r = -1.0
P[i, j, a, next_i, next_j] += 1.0/4
R[i, j, a] = r
4:值迭代
首先设定折扣因子gamma和收敛阈值theta。
折扣因子是我们考虑未来收益的比例,theta是判断迭代是否收敛的阈值。
算法逻辑是,只要不收敛,就不断的迭代值函数。
每次迭代,先初始化状态差值delta,遍历每个状态,若这个状态不在终点也不在障碍物,则遍历它的四个动作,利用动作状态值函数求这个状态下采取这个动作的值函数,并将这个值函数和上一个动作的值函数进行对比,保留这个状态下最大的值函数。在每次状态变化时,更新状态值矩阵V,直到遍历完所有状态。最后,再判断值函数的变化delta是否小于阈值theta,若小于则停止迭代,最后得到的值函数矩阵V就是最优值函数
# 定义值迭代算法的超参数
gamma = 0.9 # 折扣因子
theta = 1e-5 # 收敛阈值
# 迭代更新状态值函数
while True:
delta = 0.0 # 是什么的差值
for i in range(3):
for j in range(3):
if grid[i, j] == "X" or grid[i, j] == "G":
# 障碍物状态或终点状态,状态值为0
continue
v = V[i, j]
new_v = -np.inf
for a in range(4):
# 计算从状态s出发,执行动作a的预期回报
q = np.sum(P[i, j, a] * (R[i, j, a] + gamma * V))
if q > new_v:
new_v = q
V[i, j] = new_v
delta = max(delta, abs(v - new_v))
if delta < theta:
break
至此,值迭代函数成功实现在走迷宫小游戏中。对于其他更复杂的场景,状态集可能是非常大的,需要用到剪枝方法,留待下次实现。