DQN小车爬山——pytorch实现

  最近在b站上看到了很好的DQN教程及代码实例,特此开贴记录学习笔记。
  首先先放上大神的视频链接:Python·Pytorch-一点一点学AI-5-人人都可以学会的强化学习DQN(Deep Q-Learning),特别详细。希望有兴趣的朋友前往b站支持。

gym常用环境

gym常用环境:gym常用的研究问题
打开CartPole-v1,查看其源代码如图所示:
在这里插入图片描述
在这里插入图片描述
可以在描述行中看到,该环境有4个观测值,分别是车的位置,车速,杆的角度,杆的偏转速度。2个动作分别为车向左和右走。
另外可通过以下代码查看:

import gym
env = gym.make('CartPole-v0')
print('观测空间 = {}'.format(env.observation_space))
print('动作空间 = {}'.format(env.action_space))
print('观测范围 = {}~{}'.format(env.observation_space.low,env.observation_space.high))
print('动作数 = {}'.format(env.action_space.n))

输出结果:

观测空间 = Box(4,)
动作空间 = Discrete(2)
观测范围 = [-4.8000002e+00 -3.4028235e+38 -4.1887903e-01 -3.4028235e+38]~[4.8000002e+00 3.4028235e+38 4.1887903e-01 3.4028235e+38]
动作数 = 2

运行结果告诉我们,观测空间是形状为(2,)的浮点型np.array,而动作空间是取的int型数值。

小车爬山问题

  • 这里我们考虑小车爬山问题,通过上述描述,可知小车爬山有两个状态:位置和速度。三个动作:向左,向右。。。。。所以神经网络输入为2维,输出为3维。
  • 通过环境选择动作的时候,采用的是 ε \varepsilon ε-greedy方法。即刚开始是随机选择动作,即完全探索,随机学习次数的增多,agent的行为应该越来越优化,所以 ε \varepsilon ε的值会越来越小。
  • 这里坐标的设置可能与我们想的不同,如下图所示,在x轴方向看。

在这里插入图片描述
下面是源代码里面给定的相关位置的范围。
在这里插入图片描述
所以我们有了代码中给定奖励的方式:

s_, r , done , info = env.step(a)               ##环境返回值,可查看step函数
        r = s_[0] + 0.5                        ##因为初始点位置为-0.5,+0.5保证奖励r为0。
        if s_[0] > -0.5:                      ##如果位置向右,就给奖励。
            r = s_[0] + 0.5
            if s_[0] > 0.5:                  ###到达目标,给5的奖励  
                r = 5
        else:
            r = 0                          ##在左边,不得分

源代码中对state的定义:
1

所以,是s[0]代表位置。奖励给定的方式是:向右就给奖励,向左就不给奖励。

  • DQN设置了记忆库,反复试验然后存储数据,存满后,然后随机采样。此外还设置了目标网络和当前网络和延迟更新。原因可见我的另外一篇博客。[DQN学习笔记]。
  • 此外,代码中关于gather函数的用法,可见注释和这篇博文:pytorch之gather函数
    好了,以上就是pytorch实现DQN的细节。代码如下:
import torch
import torch.nn as nn
import numpy as np
import gym
import torch.autograd
import random


class MyNet(nn.Module):
    def __init__(self):
        super(MyNet,self).__init__()
        self.fc = nn.Sequential(
            nn.Linear(2,24),    ##两个输入
            nn.ReLU(),
            nn.Linear(24,24),
            nn.ReLU(),
            nn.Linear(24,3)    ##三个输出
        )
        self.mls = nn.MSELoss()
        self.opt = torch.optim.Adam(self.parameters(),lr = 0.001)
    def forward(self,x):
        return self.fc(x)
env = gym.envs.make('MountainCar-v0')
env = env.unwrapped
net = MyNet()   #实例化
net2 = MyNet()


store_count = 0
store_size = 2000
decline = 0.6   # epsilo
learn_time = 0
updata_time = 20  #目标值网络更新步长
gama = 0.9
b_size = 1000
store = np.zeros((store_size,6))    ###[s,a,s_,r],其中s占两个,a占一个,r占一个
start_study = False

for i in range(50000):
    s = env.reset()  ##
    while True:
        ###根据 state 产生动作
        if random.randint(0,100) < 100 * (decline ** learn_time):  # 相当于epsilon
            a = random.randint(0,2)
        else:
            out = net(torch.Tensor(s)).detach()    ##detch()截断反向传播的梯度,[r1,r2]
            a = torch.argmax(out).data.item()      ##[取最大,即取最大值的index]
        s_, r , done , info = env.step(a)               ##环境返回值,可查看step函数
        r = s_[0] + 0.5
        if s_[0] > -0.5:
            r = s_[0] + 0.5
            if s_[0] > 0.5:
                r = 5
        else:
            r = 0
        # r = abs(s_[0]-(-0.5))

        store[store_count % store_size][0:2] = s    ##覆盖老记忆
        store[store_count % store_size][2:3] = a
        store[store_count % store_size][3:5] = s_
        store[store_count % store_size][5:6] = r
        store_count +=1
        s = s_
  #####反复试验然后存储数据,存满后,就每次取随机部分采用sgd
        if store_count > store_size:
            if learn_time % updata_time ==0:
                net2.load_state_dict(net.state_dict())  ##延迟更新

            index = random.randint(0,store_size - b_size - 1)
            b_s = torch.Tensor(store[index:index + b_size,0:2])
            b_a = torch.Tensor(store[index:index + b_size, 2:3]).long()  ##  因为gather的原因,索引值必须是longTensor
            b_s_ = torch.Tensor(store[index:index + b_size, 3:5])
            b_r = torch.Tensor(store[index:index + b_size, 5:6 ])  #取batch数据

            q = net(b_s).gather(1,b_a) #### 聚合形成一张q表    根据动作得到的预期奖励是多少
            q_next = net2(b_s_).detach().max(1)[0].reshape(b_size,1)  #值和索引,延迟更新
            tq = b_r+gama * q_next
            loss = net.mls(q,tq)
            net.opt.zero_grad()
            loss.backward()
            net.opt.step()

            learn_time += 1
            if not start_study:   
                print('start_study')
                start_study  = True
                break
        if done:
            print(i)
            break

        env.render()

以下是使用PyTorch实现DQN雷达干扰决策的示例代码: ```python import torch import torch.nn as nn import torch.optim as optim import numpy as np # 定义DQN模型 class DQN(nn.Module): def __init__(self, state_dim, action_dim): super(DQN, 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 = torch.relu(self.fc1(x)) x = torch.relu(self.fc2(x)) return self.fc3(x) # 定义DQN Agent class DQNAgent: def __init__(self, state_dim, action_dim): self.state_dim = state_dim self.action_dim = action_dim self.model = DQN(state_dim, action_dim) self.target_model = DQN(state_dim, action_dim) self.optimizer = optim.Adam(self.model.parameters(), lr=0.001) self.memory = [] def act(self, state): state = torch.from_numpy(state).float().unsqueeze(0) q_values = self.model(state) return np.argmax(q_values.detach().numpy()) def remember(self, state, action, reward, next_state, done): self.memory.append((state, action, reward, next_state, done)) def replay(self, batch_size): if len(self.memory) < batch_size: return batch = random.sample(self.memory, batch_size) states, actions, rewards, next_states, dones = zip(*batch) states = torch.tensor(states).float() actions = torch.tensor(actions).long() rewards = torch.tensor(rewards).float() next_states = torch.tensor(next_states).float() dones = torch.tensor(dones).float() q_values = self.model(states) next_q_values = self.target_model(next_states) max_next_q_values = torch.max(next_q_values, dim=1)[0] targets = rewards + (1 - dones) * max_next_q_values q_values = q_values.gather(1, actions.unsqueeze(1)).squeeze(1) loss = nn.MSELoss()(q_values, targets) self.optimizer.zero_grad() loss.backward() self.optimizer.step() def update_target_model(self): self.target_model.load_state_dict(self.model.state_dict()) # 定义环境和训练过程 state_dim = 4 # 状态空间维度 action_dim = 2 # 动作空间维度 env = RadarEnv() # 自定义雷达环境类 agent = DQNAgent(state_dim, action_dim) episodes = 1000 # 训练的总回合数 batch_size = 32 # 每次训练的样本批次大小 for episode in range(episodes): state = env.reset() done = False total_reward = 0 while not done: action = agent.act(state) next_state, reward, done = env.step(action) agent.remember(state, action, reward, next_state, done) state = next_state total_reward += reward agent.replay(batch_size) agent.update_target_model() print('Episode: {}, Total Reward: {}'.format(episode, total_reward)) ``` 请注意,以上代码只是一个简单的框架,你需要根据具体的雷达干扰决策问题进行相应的环境定义和数据处理。同时,你可能需要自定义雷达环境类和相应的状态、动作表示方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

通信仿真爱好者

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

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

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

打赏作者

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

抵扣说明:

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

余额充值