动手学强化学习之强化学习进阶篇:DQN算法总结

  1. class DQN:
        ''' DQN算法 '''
        def __init__(self, state_dim, hidden_dim, action_dim, learning_rate, gamma,
                     epsilon, target_update, device):
            self.action_dim = action_dim
            self.q_net = Qnet(state_dim, hidden_dim,
                              self.action_dim).to(device)  # Q网络
            # 目标网络
            self.target_q_net = Qnet(state_dim, hidden_dim,
                                     self.action_dim).to(device)
            # 使用Adam优化器
            self.optimizer = torch.optim.Adam(self.q_net.parameters(),
                                              lr=learning_rate)
            self.gamma = gamma  # 折扣因子
            self.epsilon = epsilon  # epsilon-贪婪策略
            self.target_update = target_update  # 目标网络更新频率
            self.count = 0  # 计数器,记录更新次数
            self.device = device
    
        def take_action(self, state):  # epsilon-贪婪策略采取动作
            if np.random.random() < self.epsilon:
                action = np.random.randint(self.action_dim)
            else:
                state = torch.tensor([state], dtype=torch.float).to(self.device)# 输入到网络当中的假如是n个状态,输出的是m个动作对应的不同状态下的q-value值,先找到最大项的索引,然后取值
                action = self.q_net(state).argmax().item()
            return action
    
        def update(self, transition_dict):
            states = torch.tensor(transition_dict['states'],
                                  dtype=torch.float).to(self.device)
            actions = torch.tensor(transition_dict['actions']).view(-1, 1).to(
                self.device)
            rewards = torch.tensor(transition_dict['rewards'],
                                   dtype=torch.float).view(-1, 1).to(self.device)
            next_states = torch.tensor(transition_dict['next_states'],
                                       dtype=torch.float).to(self.device)
            dones = torch.tensor(transition_dict['dones'],
                                 dtype=torch.float).view(-1, 1).to(self.device)
    
            # gather函数第一个参数是1就代表gather的索引列表都是针对列说的,要是0就代表针对行说的 
            # 此时的actions已经是指定好了的,因为这些值都是从replay buffer当中获取的 
            # gather函数 还有一个特点 就是 结果的形状和索引列表的shape是相同的。 
            q_values = self.q_net(states).gather(1, actions)  # Q值
            # 下个状态的最大Q值
            '''
            self.target_q_net(next_states)输出的是一个包含n个状态,m个动作的张量
            .max(1)操作是在上边的n*m大小的张量中的每一行选取最大值,返回来的是一个元组(其中包括最大值和他们对应的索引两个列表 )
            [0]这个操作就是只选取最大值那个列表 
            '''
            max_next_q_values = self.target_q_net(next_states).max(1)[0].view(
                -1, 1)
            q_targets = rewards + self.gamma * max_next_q_values * (1 - dones
                                                                    )  # TD误差目标
            dqn_loss = torch.mean(F.mse_loss(q_values, q_targets))  # 均方误差损失函数
            self.optimizer.zero_grad()  # PyTorch中默认梯度会累积,这里需要显式将梯度置为0
            dqn_loss.backward()  # 反向传播更新参数
            self.optimizer.step()
    
            if self.count % self.target_update == 0:
                self.target_q_net.load_state_dict(self.q_net.state_dict())  # 更新目标网络
            self.count += 1
    
  2. 我们也可以看到,在 DQN 的性能得到提升后,它会持续出现一定程度的震荡,这主要是神经网络过拟合到一些局部经验数据后由argmax运算带来的影响。对这句话的理解

    • 神经网络过拟合到一些局部经验数据:在DQN中,深度神经网络负责逼近Q函数。如果网络过度学习(过拟合)了某些特定的经验数据(可能是由于这些数据在训练集中出现得过于频繁),它可能会在这些数据上表现得特别好,但在未见过的或不常见的数据上表现得较差。

    • 由运算带来的影响:这里指的是由于神经网络在学习过程中的这种过拟合现象,导致了算法性能的震荡。即算法在某些方面学得很好,但这可能限制了其在更广泛、更一般的情况下的适应性和灵活性。

  3. DQN的主要思想 就是 用一个神经网络来表示最优策略函数Q,然后用Q-learning的思想进行参数更新。

  4. 两个小trick : Replay Buffer 和 目标网络 两个模块

  5. class ConvolutionalQnet(torch.nn.Module):
        ''' 加入卷积层的Q网络 '''
        def __init__(self, action_dim, in_channels=4):
            super(ConvolutionalQnet, self).__init__()
            # in_channels 对于一般的输入图像而言指的是RGB三个通道,但是这里边默认值设置成了4代表着将连续4帧图像叠加在一起
            # 32就是32个卷积核 核大小是8*8 步长是4
            self.conv1 = torch.nn.Conv2d(in_channels, 32, kernel_size=8, stride=4)
            # 32就是上一层的输入通道 64就是这一层的输出通道数量
           	
            self.conv2 = torch.nn.Conv2d(32, 64, kernel_size=4, stride=2)
            self.conv3 = torch.nn.Conv2d(64, 64, kernel_size=3, stride=1)
            # 7 * 7 * 64 代表着 特征图的宽度 * 高度 * 通道数 512 代表着这一层网络的学习能力 如此设计只是出于经验  
            self.fc4 = torch.nn.Linear(7 * 7 * 64, 512)
            self.head = torch.nn.Linear(512, action_dim)
    
        def forward(self, x):
            x = x / 255
            x = F.relu(self.conv1(x))
            x = F.relu(self.conv2(x))
            x = F.relu(self.conv3(x))
            x = F.relu(self.fc4(x))
            return self.head(x)
    
  6. input output stride之间的关系: o u t p u t = i n p u t ∗ 2 s t r i d e − 1 output = input * 2^{stride - 1} output=input2stride1

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值