强化学习2.2 MDP实践——Frozen lake

问题介绍

FrozenLake 指 OpenAI Gym 库中的一个经典强化学习环境。

  • 游戏场景:玩家控制角色在一个由冰冻湖面组成的网格世界中移动,目标是从起点到达终点,同时避免掉入冰面上的洞穴。网格通常为正方形,如 4x4 或 8x8 的地图,每个方格可以是起点、终点、冰冻区域或洞穴。
  • 动作空间:动作的形状是(1,)的 int64 变量,在范围 {0,3} 内,表示玩家应该向哪个方向移动。其中 0 为向左移动,1 为向下移动,2 为向右移动,3 为向上移动。
  • 观察空间:观察值是一个 int 值,代表玩家的当前位置,计算方式为 current_row * nrows + current_col(其中行和列都从 0 开始)。例如,在 4x4 地图中的目标位置可以这样计算:3 * 4 + 3 = 15。
  • 初始状态:游戏开始时,玩家处于状态 [0],即地图的左上角位置 [0,0]。
  • 奖励机制:达到目标获得奖励 + 1,掉入洞中或到达冰冻区域奖励为 0。
  • 游戏结束条件:玩家掉入洞中或到达目标位置时,游戏终止;若使用时间限制包装器,对于 4x4 环境,情节长度为 100 步,对于 8x8 环境,情节长度为 200 步,达到步数限制时游戏结束。

使用MDP解决问题

初始化环境

python 复制代码
from mdp import FrozenLakeEnv
mdp = FrozenLakeEnv(slip_chance=0)

mdp.render()

如下图所示,F表示正常的道路,H表示洞,G表示终点。

定义价值迭代函数

python 复制代码
def value_iteration(mdp, state_values=None, gamma=0.9, num_iter=1000, min_difference=1e-5):
    """ performs num_iter value iteration steps starting from state_values. Same as before but in a function """
    state_values = state_values or {s: 0 for s in mdp.get_all_states()}
    for i in range(num_iter):

        # 计算新的状态价值:对每个状态,取所有动作的最大期望回报
        new_state_values = {}
        for s in mdp.get_all_states():
            # 终端状态(无可用动作)的价值保持为0
            if mdp.is_terminal(s):
                new_state_values[s] = 0.0
                continue
            # 遍历所有可能的动作,计算每个动作的期望回报
            action_values = []
            for a in mdp.get_possible_actions(s):
                q_val = 0.0
                # 遍历该动作下的所有转移概率和后续状态
                for prob, next_s, reward in mdp.get_transitions(s, a):
                    q_val += prob * (reward + gamma * state_values[next_s])
                action_values.append(q_val)
            # 取最大的动作价值作为当前状态的新价值
            new_state_values[s] = max(action_values)

        assert isinstance(new_state_values, dict)

        # 计算与上一轮价值的最大差异
        diff = max(abs(new_state_values[s] - state_values[s])
                   for s in mdp.get_all_states())

        print("iter %4i   |   diff: %6.5f   |   V(start): %.3f " %
              (i, diff, new_state_values[mdp._initial_state]))

        state_values = new_state_values
        if diff < min_difference:
            break

    return state_values

进行价值迭代

python 复制代码
state_values = value_iteration(mdp)

下面展示运行过程

根据当前状态和动作计算累计奖励

python 复制代码
def get_action_value(mdp, state_values, state, action, gamma):
    """ Computes Q(s,a) as in formula above """
    q_value = 0.0
    # 获取从state执行action后所有可能的下一状态
    next_states = mdp.get_next_states(state, action)
    
    for next_state in next_states:
        # 获取转移概率 P(s'|s,a)
        prob = mdp.get_transition_prob(state, action, next_state)
        # 获取即时奖励 r(s,a,s')
        reward = mdp.get_reward(state, action, next_state)
        # 累加计算 Q(s,a) = sum[ P(s'|s,a) * (r + gamma*V(s')) ]
        q_value += prob * (reward + gamma * state_values[next_state])
    
    return q_value

根据当前状态选择最优动作

python 复制代码
def get_optimal_action(mdp, state_values, state, gamma=0.9):
    """ Finds optimal action using formula above. """
    if mdp.is_terminal(state):
        return None

    # 获取当前状态下所有可能的动作
    possible_actions = mdp.get_possible_actions(state)
    
    # 计算每个动作的Q值,存储为 {动作: Q值}
    action_q = {}
    for action in possible_actions:
        q_value = get_action_value(mdp, state_values, state, action, gamma)
        action_q[action] = q_value
    
    # 选择Q值最大的动作(argmax_a Q(s,a))
    optimal_action = max(action_q, key=action_q.get)
    
    return optimal_action

下面展示通过价值迭代函数所得到的状态价值,进行游戏的过程

python 复制代码
s = mdp.reset()
mdp.render()
for t in range(100):
    a = get_optimal_action(mdp, state_values, s, gamma=0.9)
    print(a, end='\n\n')
    s, r, done, _ = mdp.step(a)
    mdp.render()
    if done:
        break

角色依据状态价值进行运动的过程如下所示

下面进行可视化,定义函数

python 复制代码
import matplotlib.pyplot as plt
%matplotlib inline


def draw_policy(mdp, state_values):
    plt.figure(figsize=(3, 3))
    h, w = mdp.desc.shape
    states = sorted(mdp.get_all_states())
    V = np.array([state_values[s] for s in states])
    Pi = {s: get_optimal_action(mdp, state_values, s, gamma) for s in states}
    plt.imshow(V.reshape(w, h), cmap='gray', interpolation='none', clim=(0, 1))
    ax = plt.gca()
    ax.set_xticks(np.arange(h)-.5)
    ax.set_yticks(np.arange(w)-.5)
    ax.set_xticklabels([])
    ax.set_yticklabels([])
    Y, X = np.mgrid[0:4, 0:4]
    a2uv = {'left': (-1, 0), 'down': (0, -1), 'right': (1, 0), 'up': (0, 1)}
    for y in range(h):
        for x in range(w):
            plt.text(x, y, str(mdp.desc[y, x].item()),
                     color='g', size=12,  verticalalignment='center',
                     horizontalalignment='center', fontweight='bold')
            a = Pi[y, x]
            if a is None:
                continue
            u, v = a2uv[a]
            plt.arrow(x, y, u*.3, -v*.3, color='m',
                      head_width=0.1, head_length=0.1)
    plt.grid(color='b', lw=2, ls='-')
    plt.show()

重新训练价值迭代函数并进行可视化

python 复制代码
state_values = {s: 0 for s in mdp.get_all_states()}

for i in range(10):
    print("after iteration %i" % i)
    state_values = value_iteration(mdp, state_values, num_iter=1)
    draw_policy(mdp, state_values)
# please ignore iter 0 at each step
定义8*8的问题,并进行可视化
python 复制代码
from IPython.display import clear_output
from time import sleep
mdp = FrozenLakeEnv(map_name='8x8', slip_chance=0.1)
state_values = {s: 0 for s in mdp.get_all_states()}

for i in range(30):
    clear_output(True)
    print("after iteration %i" % i)
    state_values = value_iteration(mdp, state_values, num_iter=1)
    draw_policy(mdp, state_values)
    sleep(0.5)
# please ignore iter 0 at each step

整体迭代过程如下所示

大规模测试

连续跑1000次进行测试

python 复制代码
mdp = FrozenLakeEnv(slip_chance=0)
state_values = value_iteration(mdp)

total_rewards = []
for game_i in range(1000):
    s = mdp.reset()
    rewards = []
    for t in range(100):
        s, r, done, _ = mdp.step(
            get_optimal_action(mdp, state_values, s, gamma=0.9))
        rewards.append(r)
        if done:
            break
    total_rewards.append(np.sum(rewards))

print("average reward: ", np.mean(total_rewards))
assert(1.0 <= np.mean(total_rewards) <= 1.0)
print("Well done!")

迭代过程如下

调整slip_chance重新进行测试,打滑概率为10%

python 复制代码
# Measure agent's average reward
mdp = FrozenLakeEnv(slip_chance=0.1)
state_values = value_iteration(mdp)

total_rewards = []
for game_i in range(1000):
    s = mdp.reset()
    rewards = []
    for t in range(100):
        s, r, done, _ = mdp.step(
            get_optimal_action(mdp, state_values, s, gamma=0.9))
        rewards.append(r)
        if done:
            break
    total_rewards.append(np.sum(rewards))

print("average reward: ", np.mean(total_rewards))
assert(0.8 <= np.mean(total_rewards) <= 0.95)
print("Well done!")

迭代过程如下

继续调整slip_chance重新进行测试,打滑概率为25%

python 复制代码
# Measure agent's average reward
mdp = FrozenLakeEnv(slip_chance=0.25)
state_values = value_iteration(mdp)

total_rewards = []
for game_i in range(1000):
    s = mdp.reset()
    rewards = []
    for t in range(100):
        s, r, done, _ = mdp.step(
            get_optimal_action(mdp, state_values, s, gamma=0.9))
        rewards.append(r)
        if done:
            break
    total_rewards.append(np.sum(rewards))

print("average reward: ", np.mean(total_rewards))
assert(0.6 <= np.mean(total_rewards) <= 0.7)
print("Well done!")

迭代过程如下

改为8*8的问题规模,定义打滑概率为20%

python 复制代码
# Measure agent's average reward
mdp = FrozenLakeEnv(slip_chance=0.2, map_name='8x8')
state_values = value_iteration(mdp)

total_rewards = []
for game_i in range(1000):
    s = mdp.reset()
    rewards = []
    for t in range(100):
        s, r, done, _ = mdp.step(
            get_optimal_action(mdp, state_values, s, gamma=0.9))
        rewards.append(r)
        if done:
            break
    total_rewards.append(np.sum(rewards))

print("average reward: ", np.mean(total_rewards))
assert(0.6 <= np.mean(total_rewards) <= 0.8)
print("Well done!")

迭代过程如下

相关推荐
JJJJ_iii3 小时前
【机器学习06】神经网络的实现、训练与向量化
人工智能·笔记·深度学习·神经网络·学习·机器学习·线性回归
倔强的石头1063 小时前
AI协作天花板!CherryStudio让多模型协同像搭积木
人工智能·cpolar
IT_陈寒3 小时前
Vite 3.0 性能优化实战:5个技巧让你的构建速度提升200% 🚀
前端·人工智能·后端
说私域4 小时前
从工具理性到价值共生:开源链动2+1模式、AI智能名片与S2B2C商城系统的社会连接重构研究
人工智能·重构·开源
heisd_14 小时前
OpenCV计算机视觉库
人工智能·opencv·计算机视觉
wb043072019 小时前
性能优化实战:基于方法执行监控与AI调用链分析
java·人工智能·spring boot·语言模型·性能优化
AAA小肥杨9 小时前
基于k8s的Python的分布式深度学习训练平台搭建简单实践
人工智能·分布式·python·ai·kubernetes·gpu
mit6.82411 小时前
[Agent可视化] 配置系统 | 实现AI模型切换 | 热重载机制 | fsnotify库(go)
开发语言·人工智能·golang
Percent_bigdata12 小时前
百分点科技发布中国首个AI原生GEO产品Generforce,助力品牌决胜AI搜索新时代
人工智能·科技·ai-native