【强化学习基础】深度强化学习介绍

举报
不去幼儿园 发表于 2024/12/02 20:12:31 2024/12/02
【摘要】 深度强化学习本文介绍:[Python] 深度Q网络(DQN)实现[Python] REINFORCE算法实现[Results] 运行结果随着深度学习的迅猛发展,深度强化学习(Deep Reinforcement Learning, DRL)将深度学习与强化学习相结合,使得处理高维状态空间成为可能。

         本篇文章是博主强化学习RL领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章强化学习:

       强化学习(2)---《【DRL】深度强化学习介绍》

【DRL】深度强化学习介绍

目录

1 深度Q网络(DQN)

           DQN的更新步骤

2 策略梯度方法

           REINFORCE算法

           演员-评论家(Actor-Critic)

3 深度强化学习的优势与挑战

[Python] 深度Q网络(DQN)实现

[Python] REINFORCE算法实现

[Results] 运行结果

[Notice]  注意事项


        随着深度学习的迅猛发展,深度强化学习(Deep Reinforcement Learning, DRL)将深度学习与强化学习相结合,使得处理高维状态空间成为可能。

编辑

1 深度Q网络(DQN)

        深度Q网络使用神经网络来近似Q值函数。DQN引入了经验重放(Experience Replay)和目标网络(Target Network)来提高学习稳定性和效率。

编辑

DQN的更新步骤

  1. 从经验池中随机抽取一个小批量的经验。
  2. 更新Q值函数,使用最小化均方误差(MSE)的方法。

[ L = \mathbb{E}_{s,a,r,s'} \left[ \left( y - Q(s,a; \theta) \right)^2 \right] ]

其中( y = R + \gamma \max_{a'} Q(s', a'; \theta^{-}) )( \theta^{-} )是目标网络的参数。

2 策略梯度方法

REINFORCE算法

REINFORCE是一种基于蒙特卡罗方法的策略梯度算法,它通过直接对策略进行参数化来优化期望回报。对于给定状态 ( s ) 和动作 ( a ),更新规则如下:

[ \nabla J(\theta) = \mathbb{E}{\tau \sim \pi\theta} \left[ G_t \nabla \log \pi_\theta(a_t | s_t) \right] ]

其中:

  • ( J(\theta) )是目标函数,表示期望累计奖励。
  • ( G_t )是从时间步 ( t ) 开始的回报。
  • ( \pi_\theta(a | s) )是在状态 ( s ) 下选择动作 ( a ) 的策略。

这种方法的优势在于它可以处理高维的动作空间,但通常收敛速度较慢。

演员-评论家(Actor-Critic)

        演员-评论家方法结合了值函数和策略优化。演员负责生成动作,而评论家则评估这些动作的质量。更新过程同时优化策略和价值估计。

  1. 演员更新:通过策略梯度法来调整策略。
  2. 评论家更新:使用时序差分方法更新值函数。

3 深度强化学习的优势与挑战

        深度强化学习的优势在于能有效处理复杂、高维的状态空间,如图像和语音等。然而,它也面临着一些挑战,例如:

  • 样本效率低:需要大量的交互样本来训练模型。
  • 收敛性问题:在某些情况下,可能会出现不稳定或不收敛的问题。
  • 超参数调优:需要仔细设置学习率、折扣因子等超参数。

[Python] 深度Q网络(DQN)实现

""" 深度Q网络(DQN)实现
    时间:2024.07.27
    环境:gym-CartPole-v1
    作者:不去幼儿园
"""
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import random
import numpy as np
from collections import deque

# 定义Q网络
class QNetwork(nn.Module):
    def __init__(self, state_size, action_size):
        super(QNetwork, self).__init__()
        # 第一层全连接层,将输入状态映射到64个隐藏单元
        self.fc1 = nn.Linear(state_size, 64)
        # 第二层全连接层,将64个隐藏单元映射到另一个64个隐藏单元
        self.fc2 = nn.Linear(64, 64)
        # 输出层,将隐藏单元映射到动作空间的大小
        self.fc3 = nn.Linear(64, action_size)

    def forward(self, x):
        # 前向传播:使用ReLU激活函数
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        return self.fc3(x)

# DQN代理
class DQNAgent:
    def __init__(self, state_size, action_size):
        self.state_size = state_size  # 状态空间的大小
        self.action_size = action_size  # 动作空间的大小
        # 初始化Q网络和目标Q网络
        self.qnetwork = QNetwork(state_size, action_size)
        self.target_qnetwork = QNetwork(state_size, action_size)
        # 优化器使用Adam
        self.optimizer = optim.Adam(self.qnetwork.parameters(), lr=0.001)
        # 经验回放缓冲区,最大长度为2000
        self.memory = deque(maxlen=2000)
        self.gamma = 0.99  # 折扣因子
        self.epsilon = 1.0  # 探索率
        self.epsilon_decay = 0.995  # 探索率衰减
        self.epsilon_min = 0.01  # 最小探索率
        self.batch_size = 64  # 批次大小
        self.update_target_every = 5  # 每5次更新目标网络
        self.update_count = 0  # 更新计数器

    def remember(self, state, action, reward, next_state, done):
        # 将经验存储到记忆中
        state = np.array(state, dtype=np.float32)
        next_state = np.array(next_state, dtype=np.float32)
        self.memory.append((state, action, reward, next_state, done))

    def act(self, state):
        # 使用epsilon-greedy策略选择动作
        if np.random.rand() <= self.epsilon:
            return random.choice(range(self.action_size))  # 随机选择动作
        state = torch.FloatTensor(state).unsqueeze(0)
        with torch.no_grad():
            q_values = self.qnetwork(state)
        return np.argmax(q_values.numpy())  # 选择Q值最大的动作

    def replay(self):
        # 经验回放
        if len(self.memory) < self.batch_size:
            return
        batch = random.sample(self.memory, self.batch_size)
        states, actions, rewards, next_states, dones = zip(*batch)

        states = np.array(states, dtype=np.float32)
        actions = np.array(actions)
        rewards = np.array(rewards, dtype=np.float32)
        next_states = np.array(next_states, dtype=np.float32)
        dones = np.array(dones, dtype=np.float32)

        states = torch.FloatTensor(states)
        actions = torch.LongTensor(actions).unsqueeze(1)
        rewards = torch.FloatTensor(rewards)
        next_states = torch.FloatTensor(next_states)
        dones = torch.FloatTensor(dones)

        # 计算当前Q值
        q_values = self.qnetwork(states).gather(1, actions).squeeze()
        # 计算目标Q值
        with torch.no_grad():
            next_q_values = self.target_qnetwork(next_states).max(1)[0]
            targets = rewards + (self.gamma * next_q_values * (1 - dones))

        # 计算损失并进行反向传播
        loss = nn.MSELoss()(q_values, targets)
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

        # 更新epsilon
        if self.epsilon > self.epsilon_min:
            self.epsilon *= self.epsilon_decay

        self.update_count += 1
        # 更新目标网络
        if self.update_count % self.update_target_every == 0:
            self.target_qnetwork.load_state_dict(self.qnetwork.state_dict())

# 训练DQN的主函数
def train_dqn(env_name, n_episodes=1000):
    env = gym.make(env_name, render_mode="human")  # 创建环境并设置渲染模式
    agent = DQNAgent(env.observation_space.shape[0], env.action_space.n)  # 初始化代理

    for episode in range(n_episodes):
        state, _ = env.reset()  # 重置环境并获取初始状态
        total_reward = 0
        done = False

        while not done:
            action = agent.act(state)  # 根据策略选择动作
            step_result = env.step(action)  # 执行动作
            if len(step_result) == 5:  # 如果返回5个值
                next_state, reward, done, truncated, _ = step_result
            else:
                next_state, reward, done, _ = step_result

            agent.remember(state, action, reward, next_state, done)  # 存储经验
            agent.replay()  # 经验回放
            state = next_state  # 更新状态
            total_reward += reward

        # 每训练100轮显示一次运行界面
        if (episode + 1) % 100 == 0:
            env.render()

        print(f"第 {episode + 1} 轮,总奖励: {total_reward}")

    env.close()  # 关闭环境

train_dqn('CartPole-v1')  # 开始训练

[Python] REINFORCE算法实现

""" REINFORCE算法实现
    时间:2024.07.27
    环境:gym-CartPole-v1
    作者:不去幼儿园
"""
import gym
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np

# 定义策略网络
class PolicyNetwork(nn.Module):
    def __init__(self, state_size, action_size):
        super(PolicyNetwork, self).__init__()
        self.fc1 = nn.Linear(state_size, 64)  # 第一层全连接层
        self.fc2 = nn.Linear(64, action_size)  # 输出层

    def forward(self, x):
        x = torch.relu(self.fc1(x))  # 使用ReLU激活函数
        return torch.softmax(self.fc2(x), dim=-1)  # 使用Softmax输出概率分布

# REINFORCE代理
class REINFORCEAgent:
    def __init__(self, state_size, action_size):
        self.policy_network = PolicyNetwork(state_size, action_size)  # 初始化策略网络
        self.optimizer = optim.Adam(self.policy_network.parameters(), lr=0.001)  # 使用Adam优化器
        self.gamma = 0.99  # 折扣因子

    def select_action(self, state):
        state = torch.FloatTensor(state).unsqueeze(0)  # 转换状态为张量,并增加一个维度
        probs = self.policy_network(state)  # 获取动作概率
        action = np.random.choice(len(probs[0]), p=probs.detach().numpy()[0])  # 根据概率选择动作
        return action, torch.log(probs[0, action])  # 返回动作和对应的对数概率

    def update_policy(self, rewards, log_probs):
        discounted_rewards = []  # 初始化折扣奖励列表
        R = 0  # 初始化累计奖励
        for r in reversed(rewards):  # 计算折扣奖励
            R = r + self.gamma * R
            discounted_rewards.insert(0, R)  # 插入到列表的开头
        discounted_rewards = torch.FloatTensor(discounted_rewards)  # 转换为张量
        # 标准化奖励
        discounted_rewards = (discounted_rewards - discounted_rewards.mean()) / (discounted_rewards.std() + 1e-9)
        log_probs = torch.stack(log_probs)  # 将对数概率堆叠成一个张量
        loss = -torch.sum(log_probs * discounted_rewards)  # 计算损失
        self.optimizer.zero_grad()  # 清零梯度
        loss.backward()  # 反向传播
        self.optimizer.step()  # 更新参数

# 训练REINFORCE的主函数
def train_reinforce(env_name, n_episodes=1000):
    render = False  # 初始化渲染标志为False
    for episode in range(n_episodes):
        if (episode + 1) % 100 == 0:  # 每训练100轮设置渲染标志为True
            render = True
        else:
            render = False

        # 创建环境,并根据渲染标志设置渲染模式
        env = gym.make(env_name, render_mode="human" if render else None)
        agent = REINFORCEAgent(env.observation_space.shape[0], env.action_space.n)  # 初始化代理

        state, _ = env.reset()  # 重置环境并获取初始状态
        log_probs = []  # 初始化对数概率列表
        rewards = []  # 初始化奖励列表
        total_reward = 0  # 初始化总奖励
        done = False  # 初始化完成标志为False

        while not done:
            if render:
                env.render()  # 如果渲染标志为True,渲染环境

            action, log_prob = agent.select_action(state)  # 选择动作
            next_state, reward, done, truncated, _ = env.step(action)  # 执行动作
            log_probs.append(log_prob)  # 存储对数概率
            rewards.append(reward)  # 存储奖励
            state = next_state  # 更新状态
            total_reward += reward  # 更新总奖励

        agent.update_policy(rewards, log_probs)  # 更新策略
        print(f"第 {episode + 1} 轮,总奖励: {total_reward}")  # 输出本集总奖励

        if render:
            env.close()  # 如果渲染标志为True,关闭环境

train_reinforce('CartPole-v1')  # 开始训练

[Results] 运行结果


[Notice]  注意事项

深度Q网络(DQN)实现注释说明:

  1. import 部分:导入所需的库,包括 gym(用于环境模拟)、torch(用于深度学习)、random 和 numpy(用于随机数生成和数值计算)、deque(用于经验回放缓冲区)。
  2. QNetwork 类:定义了Q网络的结构,包括输入层、隐藏层和输出层。
  3. DQNAgent 类:定义了DQN智能体,包括初始化、存储经验、选择动作和经验回放等方法。
  4. train_dqn 函数:主训练循环,包括环境交互、经验存储和训练。

 REINFORCE算法实现详细注释说明:

  1. 导入库

    • gym:用于创建和管理强化学习环境。
    • torch 和 torch.nn:用于构建和训练神经网络。
    • torch.optim:用于优化神经网络参数。
    • numpy:用于数值计算和数组操作。
  2. PolicyNetwork

    • 定义了一个两层全连接的神经网络,输出动作的概率分布。
    • 使用ReLU激活函数和Softmax输出层。
  3. REINFORCEAgent

    • 初始化策略网络和优化器。
    • select_action 方法基于策略网络输出的概率分布选择动作,并返回该动作和对应的对数概率。
    • update_policy 方法计算每个步骤的折扣奖励,并使用标准化后的折扣奖励更新策略网络的参数。
  4. train_reinforce 函数

    • 初始化渲染标志 render
    • 每训练100轮设置渲染标志为True。
    • 创建环境时,根据渲染标志设置 render_mode 为 "human" 或 None
    • 在每一步中选择动作,执行动作,存储对数概率和奖励,更新状态,并在需要时渲染环境。
    • 在每个回合结束时,调用 update_policy 更新策略网络。
    • 在渲染标志为True时,关闭环境以等待下次再打开。

     文章若有不当和不正确之处,还望理解与指出。由于部分文字、图片等来源于互联网,无法核实真实出处,如涉及相关争议,请联系博主删除。如有错误、疑问和侵权,欢迎评论留言联系作者,或者添加VX:Rain21321_2,联系作者。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。