Pytorch的学习——DQN

DQN

DQN是强化学习的一种强大的武器,其融合了神经网络和Q-learning的方法, 有一个记忆库用于学习经历。
Q learning 是一种 off-policy 离线学习法, 它能学习当前经历着的, 也能学习过去经历过的, 甚至是学习别人的经历. 所以每次 DQN 更新的时候, 我们都可以随机抽取一些之前的经历进行学习. 随机抽取这种做法打乱了经历之间的相关性, 也使得神经网络更新更有效率.。
Fixed Q-targets 也是一种打乱相关性的机理, 如果使用 fixed Q-targets, 我们就会在 DQN 中使用到两个结构相同但参数不同的神经网络, 用来预测估计值的神经网络具备最新的参数, 而预测现实值的神经网络使用的参数则是很久以前的。

例子

这里小编通过一个神经网络做实验的列子来更加形象的了解DQN,其中用到一个gym库用来提供实验场所

import torch
import torch.nn as nn
import torch.nn.functional as F
import numpy as np
import gym     # 通过pip安装就行了


BATCH_SIZE = 32             # 批处理时,每次提取的数据个数,这里是图片的个数
LR = 0.01                   # 学习效率
EPSILON = 0.9               # greedy policy
GAMMA = 0.9                 # reward discount
TARGET_REPLACE_ITER = 100   # 标签更新频率
MEMORY_CAPACITY = 2000      # 记忆库的大小

# 加载实验场所,这里是一个竖杆子的游戏
env = gym.make('CartPole-v0') 
env = env.unwrapped
#实验反馈的动作和实验场所的参数
N_ACTIONS = env.action_space.n
N_STATES = env.observation_space.shape[0]
# 确认shape
ENV_A_SHAPE = 0 if isinstance(env.action_space.sample(), int) else env.action_space.sample().shape

# 定义神经网络
class Net(nn.Module):
    def __init__(self, ):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(N_STATES, 50)
        self.fc1.weight.data.normal_(0, 0.1)   # 初始化
        self.out = nn.Linear(50, N_ACTIONS)
        self.out.weight.data.normal_(0, 0.1)   # 初始化

    def forward(self, x):
        x = self.fc1(x)
        x = F.relu(x)
        actions_value = self.out(x)
        return actions_value

# 定义DQN
class DQN(object):
    def __init__(self):
        # 建立两个神经网络eval_net中的参数是最新的,target_net中的参数是较旧的
        self.eval_net, self.target_net = Net(), Net()

        self.learn_step_counter = 0                                     # 用于target更新,用来记录到第几步
        self.memory_counter = 0                                         # 用来记录记忆在记忆库的位置
        self.memory = np.zeros((MEMORY_CAPACITY, N_STATES * 2 + 2))     # 初始化内存        
        self.optimizer = torch.optim.Adam(self.eval_net.parameters(), lr=LR)   # 选择优化器
        self.loss_func = nn.MSELoss()                                          # 选择计算误差的工具
     
    # 选择神经网络下一个要做的动作
    def choose_action(self, x):
        # 输入的观测值
        x = torch.unsqueeze(torch.FloatTensor(x), 0)
        # 
        if np.random.uniform() < EPSILON:   # 选取最高价值动作
            actions_value = self.eval_net.forward(x)
            action = torch.max(actions_value, 1)[1].data.numpy()
            action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)  # return the argmax index
        else:   # 否则随机选取动作
            action = np.random.randint(0, N_ACTIONS)
            action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
        return action

    # 记忆库,用来存储记忆
    def store_transition(self, s, a, r, s_):
        transition = np.hstack((s, [a, r], s_))
        # 当记忆超过记忆上线即2000,用新的记忆替换旧的记忆
        index = self.memory_counter % MEMORY_CAPACITY
        self.memory[index, :] = transition
        self.memory_counter += 1

    # 强化学习
    def learn(self):
        # 判断目标的参数更新,这里是每100步更新一次
        if self.learn_step_counter % TARGET_REPLACE_ITER == 0:
            # 用eval_net更新target_net的参数
            self.target_net.load_state_dict(self.eval_net.state_dict())
        self.learn_step_counter += 1

        # 样本批次转换类型
        sample_index = np.random.choice(MEMORY_CAPACITY, BATCH_SIZE)   # 随机抽取
        b_memory = self.memory[sample_index, :]
        b_s = torch.FloatTensor(b_memory[:, :N_STATES])
        b_a = torch.LongTensor(b_memory[:, N_STATES:N_STATES+1].astype(int))
        b_r = torch.FloatTensor(b_memory[:, N_STATES+1:N_STATES+2])
        b_s_ = torch.FloatTensor(b_memory[:, -N_STATES:])

        # deep Q-learning的学习过程
        q_eval = self.eval_net(b_s).gather(1, b_a)  # 当初选择的动作的价值
        q_next = self.target_net(b_s_).detach()     # 下一个状态的价值,detach()是为了将target_net从计算图纸上分离,不让网络更新,因为target_net是在self.target_net.load_state_dict(self.eval_net.state_dict())时进行更新
        q_target = b_r + GAMMA * q_next.max(1)[0].view(BATCH_SIZE, 1)   # 选择下一次最大价值的动作
        # 计算误差
        loss = self.loss_func(q_eval, q_target)

       # 梯度归零,误差反向传递,更新神经网络
        self.optimizer.zero_grad()
        loss.backward()
        self.optimizer.step()

# 实例化
dqn = DQN()

print('\nCollecting experience...')
# 学习的过程
for i_episode in range(400):
    s = env.reset()     # 神经网络与环境互动得到的反馈,就是现在实验内容所处的状态
    ep_r = 0
    while True:
        env.render()    # 渲染,用于可视化
        a = dqn.choose_action(s)   # 根据环境的2反馈采取的行为
        # 环境根据行为给的反馈,s_就是再次得到的状态,r就是环境对本次动作给予的奖励,以此判断采取的动作的正确性
        s_, r, done, info = env.step(a) 

        # 修改奖励,这里如果不进行这几步会报错
        x, x_dot, theta, theta_dot = s_
        r1 = (env.x_threshold - abs(x)) / env.x_threshold - 0.8
        r2 = (env.theta_threshold_radians - abs(theta)) / env.theta_threshold_radians - 0.5
        r = r1 + r2

        # 将数据放入记忆库
        dqn.store_transition(s, a, r, s_)

        ep_r += r
        # if是用来制造初始记忆的当记忆库没有超过MEMORY_CAPACITY时会不对的开始新实验制造初始记忆
        if dqn.memory_counter > MEMORY_CAPACITY:
            dqn.learn()   # 学习记忆
            if done:
                print('Ep: ', i_episode,
                      '| Ep_r: ', round(ep_r, 2))

        # 这回合结束进入下一回合
        if done:
            break
        # 将当前状态作为下一回合的初始状态
        s = s_

效果

运行程序会出现下图效果,一开始杆子会左右剧烈摇晃,然后经过神经网络的逐渐学习后杆子不再剧烈摇晃,并且坚持的时间越来越长
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DQN(Deep Q-Network)是一种使用深度神经网络实现的强化学习算法,用于解决离散动作空间的问题。在PyTorch中实现DQN可以分为以下几个步骤: 1. 定义神经网络:使用PyTorch定义一个包含多个全连接层的神经网络,输入为状态空间的维度,输出为动作空间的维度。 ```python import torch.nn as nn import torch.nn.functional as F class QNet(nn.Module): def __init__(self, state_dim, action_dim): super(QNet, self).__init__() self.fc1 = nn.Linear(state_dim, 64) self.fc2 = nn.Linear(64, 64) self.fc3 = nn.Linear(64, action_dim) def forward(self, x): x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x ``` 2. 定义经验回放缓存:包含多条经验,每条经验包含一个状态、一个动作、一个奖励和下一个状态。 ```python import random class ReplayBuffer(object): def __init__(self, max_size): self.buffer = [] self.max_size = max_size def push(self, state, action, reward, next_state): if len(self.buffer) < self.max_size: self.buffer.append((state, action, reward, next_state)) else: self.buffer.pop(0) self.buffer.append((state, action, reward, next_state)) def sample(self, batch_size): state, action, reward, next_state = zip(*random.sample(self.buffer, batch_size)) return torch.stack(state), torch.tensor(action), torch.tensor(reward), torch.stack(next_state) ``` 3. 定义DQN算法:使用PyTorch定义DQN算法,包含训练和预测两个方法。 ```python class DQN(object): def __init__(self, state_dim, action_dim, gamma, epsilon, lr): self.qnet = QNet(state_dim, action_dim) self.target_qnet = QNet(state_dim, action_dim) self.gamma = gamma self.epsilon = epsilon self.lr = lr self.optimizer = torch.optim.Adam(self.qnet.parameters(), lr=self.lr) self.buffer = ReplayBuffer(100000) self.loss_fn = nn.MSELoss() def act(self, state): if random.random() < self.epsilon: return random.randint(0, action_dim - 1) else: with torch.no_grad(): q_values = self.qnet(state) return q_values.argmax().item() def train(self, batch_size): state, action, reward, next_state = self.buffer.sample(batch_size) q_values = self.qnet(state).gather(1, action.unsqueeze(1)).squeeze(1) target_q_values = self.target_qnet(next_state).max(1)[0].detach() expected_q_values = reward + self.gamma * target_q_values loss = self.loss_fn(q_values, expected_q_values) self.optimizer.zero_grad() loss.backward() self.optimizer.step() def update_target_qnet(self): self.target_qnet.load_state_dict(self.qnet.state_dict()) ``` 4. 训练模型:使用DQN算法进行训练,并更新目标Q网络。 ```python dqn = DQN(state_dim, action_dim, gamma=0.99, epsilon=1.0, lr=0.001) for episode in range(num_episodes): state = env.reset() total_reward = 0 for step in range(max_steps): action = dqn.act(torch.tensor(state, dtype=torch.float32)) next_state, reward, done, _ = env.step(action) dqn.buffer.push(torch.tensor(state, dtype=torch.float32), action, reward, torch.tensor(next_state, dtype=torch.float32)) state = next_state total_reward += reward if len(dqn.buffer.buffer) > batch_size: dqn.train(batch_size) if step % target_update == 0: dqn.update_target_qnet() if done: break dqn.epsilon = max(0.01, dqn.epsilon * 0.995) ``` 5. 测试模型:使用训练好的模型进行测试。 ```python total_reward = 0 state = env.reset() while True: action = dqn.act(torch.tensor(state, dtype=torch.float32)) next_state, reward, done, _ = env.step(action) state = next_state total_reward += reward if done: break print("Total reward: {}".format(total_reward)) ``` 以上就是在PyTorch中实现DQN强化学习的基本步骤。需要注意的是,DQN算法中还有很多细节和超参数需要调整,具体实现过程需要根据具体问题进行调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值