Redian新闻
>
强化学习第十三篇:使用深度学习解决迷宫问题,完整步骤和代码

强化学习第十三篇:使用深度学习解决迷宫问题,完整步骤和代码

科学

你好,我是郭震

前面强化学习推送到第十二篇,迷宫问题已使用Q-learning解决过,今天使用另一种方法:深度Q网络,简称DQN网络解决。

什么是DQN?

深度Q网络(Deep Q-Network, DQN)是一种结合了深度学习和强化学习的算法,旨在解决具有高维观测空间的决策问题。它是由DeepMind在2015年提出的,用于成功地在多个Atari 2600游戏上训练智能体,实现了超越人类玩家的性能。DQN成为了深度强化学习领域的一个重要里程碑,开启了使用深度学习方法解决复杂强化学习问题的新纪元。

DQN在许多领域展现了其强大的能力,包括但不限于游戏玩法、机器人控制和自动驾驶。DQN及其变种(如Double DQNDueling DQN等)为后续深度强化学习研究和应用提供了坚实的基础,推动了该领域的快速发展。

DQN 原理?

DQN的核心思想是使用一个深度神经网络来近似Q函数(动作价值函数),这个Q函数预测在给定状态下采取每个可能动作的预期回报(累积奖励)。传统的Q学习算法依赖于一个Q表来存储和更新每个状态-动作对的Q值,但这种方法在面对高维状态空间时变得不切实际。DQN通过使用深度神经网络来克服这个限制,使得可以处理复杂、高维的输入状态,如图像。

关键创新

DQN引入了几个关键的创新来增强学习的稳定性和效率:

  • 经验回放(Experience Replay):智能体的经验(状态、动作、奖励和下一个状态)在每个时间步被存储在一个回放缓冲区中。训练网络时,会从这个缓冲区中随机抽取一小批经验进行学习,这有助于打破经验之间的相关性,并使得每个经验可以被多次重复使用,提高数据效率。

  • 固定Q目标(Fixed Q-targets):为了减少训练过程中的目标Q值与预测Q值之间的相关性,DQN使用了两个网络:一个用于当前步骤的Q值预测,另一个用于计算目标Q值。目标网络的权重定期(而非每步)从预测网络复制过来,从而增加学习的稳定性。

DQN求解迷宫问题

要使用深度Q网络(DQN)解决迷宫问题,我们首先需要建立一个环境类,该类能够处理与智能体的交互:提供状态、接受动作、返回新状态和奖励等。接着,我们将使用DQN来学习在该环境中达到目标的策略。

使用模块:

import numpy as np
import torch.nn as nn
import torch
from torch.optim import Adam
from collections import deque
import random
import matplotlib.pyplot as plt

步骤一:定义迷宫环境类

class MazeEnv:
    def __init__(self):
        self.exit_coord = (3, 3)
        self.row_n, self.col_n = 4, 4
        self.walls = {(0, 3), (1, 0), (1, 2), (2, 2), (3, 0)}
        self.state = (0, 0)  # 初始状态
        self.actions = [0, 1, 2, 3]  # 上、下、左、右
        self.reset()

    def reset(self):
        self.state = (0, 0)  # 重置智能体的位置到起点
        return self.state

    def step(self, action):
        row, col = self.state
        if action == 0:  # 上
            next_state = (max(row - 1, 0), col)
        elif action == 1:  # 下
            next_state = (min(row + 1, self.row_n - 1), col)
        elif action == 2:  # 左
            next_state = (row, max(col - 1, 0))
        elif action == 3:  # 右
            next_state = (row, min(col + 1, self.col_n - 1))
        else:
            raise ValueError("Invalid action")

        reward = -1  # 默认奖励
        done = False
        if next_state in self.walls:
            reward = -10
        elif next_state == self.exit_coord:
            reward = 10
            done = True

        self.state = next_state if next_state not in self.walls else self.state
        return self.state, reward, done

    def get_state_size(self):
        return self.row_n * self.col_n

    def get_action_size(self):
        return len(self.actions)

步骤二:定义DQN神经网络模型

# DQN模型
class DQN(nn.Module):
    def __init__(self, input_dim, output_dim):
        super(DQN, self).__init__()
        self.fc1 = nn.Linear(input_dim, 128)
        self.fc2 = nn.Linear(128, 128)
        self.fc3 = nn.Linear(128, output_dim)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        output = self.fc3(x)
        return output

步骤三:定义经验回收

# 经验回放
class ReplayBuffer:
    def __init__(self, capacity):
        self.buffer = deque(maxlen=capacity)

    def push(self, state, action, reward, next_state, done):
        self.buffer.append((state, action, reward, next_state, done))

    def sample(self, batch_size):
        state, action, reward, next_state, done = zip(*random.sample(self.buffer, batch_size))
        return np.array(state), action, reward, np.array(next_state), done

    def __len__(self):
        return len(self.buffer)

步骤四:定义更新DQN函数

def update_model(dqn_model, target_dqn_model, replay_buffer, optimizer, batch_size, gamma):
    # 从经验回放缓冲区中随机采样一批经验
    state, action, reward, next_state, done = replay_buffer.sample(batch_size)

    # 转换列表为Tensor
    state = torch.FloatTensor(state)
    action = torch.LongTensor(action)
    reward = torch.FloatTensor(reward)
    next_state = torch.FloatTensor(next_state)
    done = torch.FloatTensor(done)

    # 计算当前状态下,采取实际动作的Q值
    current_q_values = dqn_model(state).gather(1, action.unsqueeze(1)).squeeze(1)

    # 使用目标DQN模型计算下一状态的最大Q值
    next_q_values = target_dqn_model(next_state).max(1)[0]
    # 计算期望Q值
    expected_q_values = reward + gamma * next_q_values * (1 - done)

    # 计算损失
    loss = torch.nn.functional.mse_loss(current_q_values, expected_q_values.detach())

    # 优化器梯度归零
    optimizer.zero_grad()
    # 反向传播
    loss.backward()
    # 更新模型权重
    optimizer.step()

步骤五:训练DQN

# 训练DQN
def train_dqn(epochs=300):
    global epsilon
    for epoch in range(epochs):
        state = env.reset()
        state = np.eye(env.row_n * env.col_n)[state[0] * env.col_n + state[1]]
        total_reward = 0
        done = False

        while not done:
            if random.random() < epsilon:
                action = random.choice(env.actions)
            else:
                q_values = dqn_model(torch.FloatTensor(state).unsqueeze(0))
                action = torch.argmax(q_values).item()

            next_state, reward, done = env.step(action)
            next_state = np.eye(env.row_n * env.col_n)[next_state[0] * env.col_n + next_state[1]]
            replay_buffer.push(state, action, reward, next_state, done)
            state = next_state
            total_reward += reward

            if len(replay_buffer) > batch_size:
                update_model(dqn_model, target_dqn_model, replay_buffer, optimizer, batch_size, gamma)

        epsilon = max(epsilon_min, epsilon_decay * epsilon)
        print(f'Epoch: {epoch}, Total Reward: {total_reward}')
        reward_list.append(total_reward)

        if epoch % 10 == 0:
            target_dqn_model.load_state_dict(dqn_model.state_dict())

步骤六:结果分析

if __name__ == "__main__":
    # 初始化环境
    env = MazeEnv()

    # 初始化DQN
    state_size = env.get_state_size()
    action_size = env.get_action_size()

    dqn_model = DQN(input_dim=state_size, output_dim=action_size)
    target_dqn_model = DQN(input_dim=state_size, output_dim=action_size)
    target_dqn_model.load_state_dict(dqn_model.state_dict())

    optimizer = Adam(dqn_model.parameters(), lr=1e-4)
    replay_buffer = ReplayBuffer(10000)
    batch_size = 64
    gamma = 0.99
    epsilon = 1.0
    epsilon_min = 0.01
    epsilon_decay = 0.995

    reward_list = []

    train_dqn()

    x = range(len(reward_list))
    plt.plot(x, reward_list, label='Line', color='blue')
    plt.xlabel("step")
    plt.ylabel("reward")
    plt.title("DQN to solve the 4*4 maze problem")
    plt.show()

以上代码可运行,绘制step vs reward 折线图,看到奖励逐渐变大且最终收敛,大概在200时步。

使用得到的模型,预测最优迷宫行走路径:

def simulate_optimal_path(model, env):
    state = env.reset()
    optimal_path = [state]  # 记录最优路径的状态
    done = False
    while not done:
        state = np.eye(env.row_n * env.col_n)[state[0] * env.col_n + state[1]]
        state_tensor = torch.FloatTensor(state).unsqueeze(0)
        with torch.no_grad():
            action = model(state_tensor).max(1)[1].view(1, 1)
        next_state, _, done = env.step(action.item())
        optimal_path.append(next_state)
        state = next_state
    return optimal_path

调用:

optimal_path = simulate_optimal_path(dqn_model, env)
print(optimal_path)

打印出来的最优行走路线:

[(0, 0), (0, 1), (1, 1), (2, 1), (3, 1), (3, 2), (3, 3)]

也就是下图中的行走路线:

以上,使用DQN求解迷宫问题的完整步骤和代码。

下期再见!

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
加州州长纽森新年预算提案:耗资153亿美元解决无家可归问题,提升公共安全“不要害怕问题,大多数问题都有解决方案”深度学习近10年,10篇必读论文总结春节过年:使用红包教导孩子们认识金钱《幺妹和市场街》(9)述评:质疑主流媒体没问题,转向做塔克·卡尔森的听众才是问题年度代码翻车现场 |前端代码评审问题总结AI客服害了多少人?胡说八道,不解决问题,还让公司亏了1000亿解析《心迷宫》如何成为国产黑马的?新州财长警告:若不解决住房问题,悉尼将成下一个旧金山《持恆》巴郞火山引擎国际深度学习图像压缩挑战赛蝉联冠军NUS刘老师1v1科研:使用深度学习进行动态套期保值|收获一作论文与导师推荐信!《阴阳鱼》连载第16章:时间如刀,空间如砧板,而你我都不过是鱼肉归来花满树,携手再破千层浪——第十三届中国胸痛中心大会开幕式顺利举行小学英文写作课程:使用头韵(Alliteration)技巧!为细菌设计的迷宫,让它们无法感染人体从零构建现代深度学习框架(TinyDL-0.01)活动 | 3.23-24 应权通变、殊途同归——哥伦比亚中国论坛即将启幕,完整嘉宾阵容揭晓美股基本面 - 2024_02_03 * 晨报 * 全场高呼AVP!苹果首款头显上市,库克:这是明天的技术,定价合理。纽约社区26岁的他,任知名高校副教授!要解决天气预报“报不准”问题,曾因年龄小被质疑能否带好学生从框架到经典方法,全面了解分布式深度强化学习DDRL提拉米苏的寂静欢喜机器学习测试:使用模拟器测试训练好的功能的见解和经验在堪培拉,留学生竟然也可以办理本地身份证明?!出门再也不用带护照了!超简单领取步骤,8刀轻松解决~全面推行AI写代码,阿里云未来20%代码由通义灵码编写;阿尔特曼被取消OpenAI风投部门控制权丨AIGC日报从青光眼微支架到射频能量平台,朗目医疗打造医工融合创新下的眼科微创治疗完整解决方案分析了 1.5 亿行代码发现:AI 编程助手降低代码质量身份大事,永不言弃(第12) ——— 六大难题,完胜凯旋 !!10人,2023年度中国化学会青年化学奖揭晓Jupyter notebook 配置虚拟环境,很多人都遇到这个问题,完整解决步骤!每日原则:使用助手来提高效率博士申请 | 美国佐治亚大学卢国玉老师招收计算机视觉/深度学习方向全奖博士生阿里1号AI「员工」上岗,007写代码助攻大厂程序员!炸掉祖传屎山代码,Java丝滑改Python三篇论文解决「语义分割的优化和评估」难题!鲁汶/清华/牛津等联合提出全新方法
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。