强化学习_06_pytorch-DQN实践(CartPole-v0)

笔者之前有基于传统表格方法构建过一个智能体,感兴趣的读者可以去看《强化学习_03_表格方法实践(CartPole-v0 And MontoCarlo)》
之前是限制了目标的一些状态空间训练15000轮也仅仅达到了130左右成绩。进行用DQN方法进行智能体学习。

一、构建智能体

构建智能体:

  • policy是和之前一样的。探索和利用, 就是利用的时候基于nn模型的预测
  • 主要核心:
    • initialize: 初始化,基于第一批缓存数据训练数据标准化的参数,以及初始化QNet
    • update: 更新状态的预估值Q
      • Q<s, a, t> = R<s, a, t> + gamma * Q<s+1, a_max, t+1>
      • Q<s, a, t>基于batch样本中的state通过Q网络预测
      • Q<s+1, a, t+1>基于batch样本中的n_state通过Q网络预测
      • 然后对每个样本的状态刷新预估值
      • 用state 和 刷新的预估值去更新参数
class CartPoleActor:
    def __init__(self, epsilon, actions):
        self.actions = actions
        self.epsilon = epsilon
        self.scaler_model = None
        self.model = None
        self.initialized = False
 ...  
    def initialize(self, experiences):
        self.scaler_model = Scaler()
        self.model = QNeuralEstimator(
            input_dim=experiences[0].s.shape[0],
            hidden_layer_size=[10, 10],
            output_dim=len(self.actions)
        )
        states = t.tensor([e.s for e in experiences])
        self.scaler_model.fit(states)
        self.update([experiences[0]], gamma=0)
        self.initialized = True
        print('Done initialization. From now, begin training!')
    
    def estimate(self, s):
        s = self.scaler_model.predict(s)
        return self.model(s)
    
    def _predict(self, states):
        if self.initialized:
            return self.estimate(states)

        dim_ = len(self.actions) 
        size = dim_ * len(states)
        return np.random.uniform(size=size).reshape((-1, dim_))
    
    def update(self, batch_experiences, gamma):
        """
        更新状态的预估Q值:
        Q<s, a, t> = R<s, a, t> + gamma * Q<s+1, a_max, t+1>
        """
        states = t.tensor([e.s for e in batch_experiences])
        n_states = t.tensor([e.n_s for e in batch_experiences])

        estimateds = self.estimate(states)
        futures = self.estimate(n_states)
        for i, e in enumerate(batch_experiences):
            R = e.r
            if not e.d:
                R += gamma * t.max(futures[i])
            
            estimateds[i][e.a] = R

        estimateds = t.tensor(estimateds).float()
        self.model.fit(self.scaler_model.predict(states), estimateds)
    
    def policy(self, s):
        if random.random() < self.epsilon or not self.initialized:
            return np.random.randint(len(self.actions))
        
        estimates = self.estimate(s)
        return np.argmax(estimates.detach().numpy())

二、QNet及Scaler

2.1 Scaler

scaler 是笔者简单写的一个归一化的类

class Scaler:
    """标准化
    ta = t.tensor([range(100), range(100, 200)]).float()
    t.tensor([np.array([11, 11]), np.array([11, 11])])
    sc = Scaler()
    sc.fit(ta)
    sc.predict(ta)
    """
    def __init__(self, method='standard'):
        """torch 标准化
        """
        self.method = method

    def standard_scaler(self, tensor_in):
        self.a = t.mean(tensor_in.float(), dim=0)
        self.b = t.std(tensor_in.float(), dim=0)
    
    def fit(self, tensor_in):
        if self.method == 'standard':
            self.standard_scaler(tensor_in)

    def predict(self, tensor_in):
        if type(tensor_in) == np.ndarray:
            tensor_in = t.tensor(tensor_in)
        if self.method == 'standard':
            return (tensor_in.float() - self.a) / self.b

    def save(self, file):
        a = self.a.numpy()
        b = self.b.numpy()
        with open(file, 'w') as f:
            f.write(f'{a},{b}')

    def load(self, file):
        with open(file, 'w') as f:
            cc = f.read()
        a, b = cc.split(',')
        self.a = t.tensor(float(a)).float()
        self.b = t.tensor(float(b)).float()

2.2 QNet

其实就是一个简单的全连接线性分类器, 多增加了model_compelet 生成损失函数和优化器,还有update 可以基于一个batch的样本进行参数更新

class QNeuralEstimator(nn.Module):
    """QNet
    简单的nn回归器
    sample
        n_model = QNeuralEstimator(input_dim=3, hidden_layer_size=[16, 16], output_dim=2)
        x1 = t.tensor([[1, 2, 3], [1, 2, 3]]).float()
        y1 = t.tensor([[1, 1], [1, 1]]).float()
        n_model(x1)
        n_model.update(x1, y1)
        n_model(x1)
    """
    def __init__(self, input_dim, hidden_layer_size, output_dim):
        super(QNeuralEstimator, self).__init__()
        self.features = nn.ModuleList()
        for i, h in enumerate(hidden_layer_size):
            self.features.append(nn.ModuleDict({
                'linear': nn.Linear(input_dim, h) if not i \
                    else nn.Linear(hidden_layer_size[i-1], h),
                'linear_active': nn.ReLU(inplace=True)
            }))
        
        self.out = nn.Linear(hidden_layer_size[-1], output_dim)
        self.model_compelet()
    
    def forward(self, x):
        for layer in self.features:
            x = layer['linear'](x)
            x = layer['linear_active'](x)
        return self.out(x)
    
    def model_compelet(self):
        self.cost_func = nn.MSELoss()
        self.opt = t.optim.Adam(self.parameters(), lr=0.001)
    
    def update(self, batch_x, batch_y):
        self.opt.zero_grad()
        pred_ = self(batch_x)
        loss = self.cost_func(batch_y, pred_)
        loss.backward()
        self.opt.step()
    
    def fit(self, x, y):
        self.update(x, y)

三、模型训练

核心就是:

  • agent.initialize
  • step 其实就是重buffer中抽样进行agent.update 模型参数更新
  • 加入了严格止停,因为探索的时候采样会采样到一些在比初始化的状态均值与方差还要大的样本。
class CartPoleActorTrainer:
    def __init__(self, buffer_size=1024, batch_size=32, gamma=0.9):
        self.buffer_size = buffer_size
        self.batch_size = batch_size
        self.gamma = gamma
        self.experiences = deque(maxlen=buffer_size)
        self.training = False
        self.training_count = 0

    def train_loop(self, env, agent, episode=200, render=False):
        # 严格early_stop: 连续达到最优值8次停止迭代
        th_ = 8
        not_improve_cnt = 0
        episode_reward = deque(maxlen=2)
        episode_reward.append(0)
        for e in range(episode):
            s = env.reset()
            done = False
            step_count = 0
            episode_r = 0
            while not done:
                if render:
                    env.render()
                
                a = agent.policy(s)
                n_state, reward, done, info = env.step(a)
                episode_r += reward
                # 收集样本
                self.experiences.append(
                    Experience(s, a, reward, n_state, done)
                )
                if not self.training and \
                    len(self.experiences) == self.buffer_size:
                    agent.initialize(self.experiences)
                    self.training = True
                
                # 样本采用并进行参数更新
                self.step(agent)
                s = n_state
                step_count += 1
            else:
                self.episode_end(e, step_count)
                episode_reward.append(episode_r)
                if self.training:
                    self.training_count += 1
            
            if episode_reward[1] == episode_reward[0]:
                not_improve_cnt += 1
                print(f'keep times {not_improve_cnt}')
            else:
                not_improve_cnt = 0
            
            if not_improve_cnt == th_:
                break
                
    def train(self, env, episode_count=200, epsilon=0.1, render=False):
        actions = list(range(env.action_space.n))
        agent = CartPoleActor(epsilon, actions)
        self.train_loop(env, agent, episode_count, render)
        return agent
    
    def step(self, agent):
        if self.training:
            batch = random.sample(self.experiences, self.batch_size)
            agent.update(batch, self.gamma)
    
    def episode_end(self, episode, step_count):
        recent_idx = range(len(self.experiences) - step_count, len(self.experiences))
        recent = [self.experiences[i] for i in recent_idx]
        rewards = sum([e.r for e in recent])
        print(f'[{episode}]-Trained({self.training_count}) Reward- {rewards}')

四、观测训练出的智能体的表现

显然我们的DQN表现要好于传统方法,可以达到该游戏的奖励上限200

env = CartPoleObserver(gym.make('CartPole-v0'))
trainer = CartPoleActorTrainer(buffer_size=1024, batch_size=128, gamma=0.8)
trained_agent = trainer.train(env, episode_count=320)
trained_agent.play(env)

在这里插入图片描述

完整脚本查看笔者github: dqn_rl.py

### 回答1: DQN (Deep Q-Network) 是一种基于深度神经网络的强化学习算法,它可用于解决强化学习环境中的问题。PyTorch 是一个开源的深度学习框架,提供了一种简单而强大的方式来构建和训练神经网络模型。CartPole-v0 是 OpenAI Gym 提供的一个强化学习环境,目标是控制一个摆杆平衡在垂直位置上。 在使用 PyTorch 实现 DQN 解决 CartPole-v0 问题时,需要首先定义一个深度神经网络模型作为 Q 函数的近似。这个模型通常包含若干隐藏层和一个输出层,用于预测在给定状态下采取各个动作的 Q 值。 然后,需要定义一个经验回放(Experience Replay)的缓冲区,用于存储智能体在环境中的经验,包括当前状态、动作、奖励和下一个状态。 接下来,使用 epsilon-greedy 策略选择动作,epsilon 表示随机探索的概率,即以一定概率选择随机动作,以一定概率选择当前 Q 值最大的动作。 将选择的动作应用于环境中,观察下一状态和奖励,并将这些经验存储到经验回放缓冲区中。 每隔一定步数,从经验回放缓冲区中采样一批数据,然后利用这些样本数据来更新神经网络的参数。DQN 使用经验回放的方式进行训练,这样可以减少样本间的相关性,提高样本的利用效率。 通过反向传播算法计算损失函数,并利用优化器更新神经网络的参数,使得神经网络的输出 Q 值逼近真实的 Q 值。 重复进行上述步骤,直到智能体能够有效地平衡摆杆,或者达到预定的训练次数。 在实际实现 DQN 算法过程中,还需要注意学习速率、discount factor 等超参数的选择,以及选择合适的损失函数和优化器来训练神经网络模型。 总结来说,使用 PyTorch 实现 DQN 来解决 CartPole-v0 问题,需要先定义一个深度神经网络模型作为 Q 函数的近似,然后利用经验回放的方式进行训练,通过反向传播算法来更新神经网络参数,使模型能够逼近真实的 Q 值,最终达到使摆杆平衡的目标。 ### 回答2: DQN(深度Q网络)是一种强化学习算法,用于解决各种控制问题,包括CartPole-v0这个经典的强化学习环境。PyTorch是一种深度学习框架,可以方便地构建神经网络模型。 在使用PyTorch实现DQN解决CartPole-v0问题时,我们首先需要定义网络模型。可以使用PyTorch提供的nn模块创建一个多层感知机网络,包含输入层、若干隐藏层和输出层。这个网络的输入是CartPole-v0环境的状态,输出是动作的Q值。使用ReLU作为激活函数可以增加网络的非线性表示能力。 定义好网络模型后,我们需要定义DQN的训练过程。首先,根据当前环境状态输入网络获取各个动作的Q值,然后选择Q值最大的动作作为当前的行动。执行动作后,环境将返回下一个状态、奖励和是否结束的信息。将这些信息存储在经验回放缓冲区中。 接下来,我们从经验回放缓冲区中随机采样一批数据,包括之前的状态、行动、奖励和下一个状态。然后,使用目标网络(Target Network)计算下一个状态的Q值,并根据贝尔曼方程计算当前状态的目标Q值。通过最小化当前状态的动作Q值和目标Q值的差距,更新网络的参数。 在DQN的训练过程中,还需要设置超参数,包括学习率、批大小、epsilon-greedy策略的参数等。为了提高收敛速度和稳定性,可以使用经验回放和目标网络两个技术。 最后,通过多次迭代训练,不断优化网络参数,直到DQN模型在CartPole-v0环境上能够稳定地获得较高的得分。 总之,使用PyTorch实现DQN算法解决CartPole-v0问题需要定义网络模型、训练过程和超参数,并使用经验回放和目标网络等技术进行优化,以提高性能和稳定性。 ### 回答3: DQN是一种使用深度神经网络进行强化学习的算法,它使用PyTorch框架实现,在CartPole-v0环境中非常有用。 CartPole-v0是一个经典的强化学习问题,任务是控制一个平衡杆,使其在变化的条件下保持平衡。这个环境具有四个状态变量:杆的角度、杆的速度、小车的位置和小车的速度。在每个时间步骤,智能体可以向左或向右施加力来控制小车的动作。目标是使杆保持在竖直位置,并且尽可能长时间地保持平衡。 DQN算法使用了深度神经网络来估计每种动作的Q值函数。在PyTorch中,我们可以使用nn.Module类创建深度神经网络模型,可以包含一些全连接层和非线性激活函数。DQN算法还使用了经验回放机制和目标网络来提高训练效果。 在CartPole-v0中,我们可以使用PyTorch中的torchvision.transforms对环境状态进行处理。然后,我们可以使用DQN模型以一定的epsilon-greedy策略来选择动作,并与环境进行交互。每个时间步之后,我们从经验回放缓冲区中随机样本一批数据,然后计算损失并更新网络参数。我们还会定期更新目标网络的权重,以确保稳定的学习过程。 通过使用DQN算法和PyTorch框架,我们可以在CartPole-v0环境中实现高效的强化学习训练。我们可以通过调整网络结构、超参数和训练步骤来提高性能,并使智能体在该环境中获得长时间平衡杆的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Scc_hy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值