基于DQN实现立杆子游戏

设置参数,定义学习率,奖励递减值,记忆库大小等

Batch_size = 32
Lr = 0.01                                  #学习率
Epsilon = 0.9                              #最优选择动作百分比
Gamma = 0.9                                #奖励递减函数
Target_replace_iter = 100                  #Q现实网络的更新频率
Memory_capacity = 2000                     #记忆库大小
env = gym.make('CartPole-v0')              #创建立杆子游戏模型的环境
env = env.unwrapped
N_actions = env.action_space.n             #杆子能做的动作
N_states = env.observation_space.shape[0]  #杆子能获取的环境信息数
ENV_A_SHAPE = 0 if isinstance(env.action_space.sample(), int) else env.action_space.sample().shape  #确认形状大小

1.训练网络

这个代码是整个算法的训练框架。主函数部分,多少回合数可以自己设置。

在每次训练时,智能体先重置环境env.reset,刷新当前环境,并动态可视化游戏画面env.render。接着首先根据目前的输入状态s给智能体choose_action选择一个动作。

然后,将该选择的动作加到环境当中去,得到下一个状态,采取这个动作得到的奖励,当前游戏是否结束的标记done,调优项(性能表现,延迟等)。

计算其奖励函数r。

接着将状态s,动作a,奖励值r,下一个观测状态s_作为一个样本(s,a,r,s_)存储在经验复用池中。

接下来两个判断是同时进行的,判断二为真,会结束当前回合。

判断1此时是否大于回放记忆单元大小,如果大于则判定训练DQN,更新参数。否则,继续输入下一个状态给智能体choose_action选择的当前动作,以此循环。

判断2,判断是否结束当前回合,是则结束,否则继续执行上一步的功能。

最后将下一步的状态赋值给当前的状态。

当所有回合结束,则关闭env.close。

if __name__ == "__main__":
    dqn = DQN()
    print('\nCollecting experience...')
    for i_episode in range(2):                      #400个回合episode
        print("回合数为",i_episode)
        s = env.reset()                               #使得智能体重置环境函数
        print("---输入当前状态---", s)
        while True:
            #可视化展示环境
            env.render()                              #刷新当前环境,并动态显示图像函数
            ep_r = 0

            print("---输入当前状态---",s)
            a = dqn.choose_action(s)                  #输入状态,输出动作
            print("---输出当前动作---",a)

            #与环境交互,获得下一步的状态
            #将选择的动作输入给环境,环境按照这个动作走一步进入下一个状态。
            s_,r,done,info = env.step(a)              #返回值(输出):新的状态,采取这个动作得到的奖励,当前游戏是否结束,调优项(性能表现,延迟等,用于调优)
            print("---输出下一时刻状态,奖励值,当前游戏是否结束,调优项---", s_,r,done,info)
            # print("---------环境返回四个值----------")
            # print(s_,r,done,info)                     #output:[-0.02554167  0.21842566  0.00165556 -0.33730742] 1.0 False {}

            #modify the re ward
            x , x_dot ,theta ,theta_dat = s_
            # print("---------赋值下一个状态值----------")
            # print(x , x_dot ,theta ,theta_dat)         #output:0.04372354 0.17304067 0.00496224 -0.297697

            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
            print("---输出计算后的奖励---", r)

            #存记忆
            dqn.store_transition(s,a,r,s_)
            #累积奖励
            ep_r += r
            print("---输出累积后的奖励---", ep_r)
            print("---存储计数器---", dqn.memory_counter)
            print("--------------------------------------------------------------------------------------------------------")
            time.sleep(5)
            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_
    env.close()

 继承Module,实现__init__,forward两个方法。init主要是定义Net结构,forward主要给出Net的执行逻辑即流程,这里网络十分简单,一个线性层和一个输出层。

Net的执行逻辑: input state --> Linear_fc1 --> relu激活函数 --> out --> actions_value

输入输出:输入为一个状态,通过神经网络后输出该状态下所有动作值。

神经网络NN类定义如下:

class Net(nn.Module):
    """
    定义:一个隐藏层,一个输出层
    forward:Net的执行逻辑 Linear_fc1 --> relu --> out --> actions_value
    """
    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):
        #Net的执行逻辑 Linear_fc1 --> relu --> out --> actions_value
        x = self.fc1(x)                              #一个隐藏层
        x = F.relu(x)
        actions_value =self.out(x)                   #一个输出层
        return actions_value

 DQN类的实现,包括__init__,choose_action,store_transition,learn四个方法的实现

class DQN(object):
    """
    定义神经网络DQN:
       DQN当中的神经网络模式,我们将依据这个模式建立两个神经网络
       Net1:一个是现实网络(Target Network)
       Net2:另一个是估计网络(Eval Network)
    """
    def __init__(self):
        #定义参数
        self.eval_net,self.target_net = Net(),Net()                   #模型初始化。初始化main net 和target net
        self.learn_step_counter = 0                                   #for target updating 设置target更新计数器
        self.memory_counter = 0                                       #for storing memory  存储计数器
        self.memory = np.zeros((Memory_capacity,N_states*2 + 2))      #innitialize memory  记忆库初始化
        print(self.memory)                                            #shape:(2000,10)
        self.optimizer = optim.Adam(self.eval_net.parameters(),lr=Lr) #优化器
        self.loss_func = nn.MSELoss()                                 #loss定义

    #选择动作
    def choose_action(self,x):
        x = Variable(torch.unsqueeze(torch.FloatTensor(x),0))          #状态
        # print(x)
        if np.random.uniform() < Epsilon:                              #产生的随机数小于贪婪度,则选择神经网络预测的动作
            action_value = self.eval_net.forward(x)                    #在线网络
            action = torch.max(action_value, 1)[1].data.numpy()
            action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
            # print("1",action)
        else:                                                          #否则产生随机行为
            action = np.random.randint(0,N_actions)
            action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
            # print("2",action)
        # print(action)
        # exit(0)
        return action                                                   #选择动作


    def store_transition(self,s,a,r,s_):
        transition = np.hstack((s,[a,r],s_))
        index = self.memory_counter % Memory_capacity
        self.memory[index,:] = transition
        self.memory_counter += 1

    def learn(self):
        #target net update
        if self.learn_step_counter % Target_replace_iter == 0:
            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 = Variable(torch.FloatTensor(b_memory[:,:N_states]))
        b_a = Variable(torch.LongTensor(b_memory[:,N_states:N_states+1].astype(int)))
        b_r = Variable(torch.FloatTensor(b_memory[:,N_states+1:N_states+2]))
        b_s_ = Variable(torch.FloatTensor(b_memory[:,-N_states:]))

        #计算q_target,loss,反向传递
        q_eval = self.eval_net(b_s).gather(1,b_a)
        q_next = self.target_net(b_s_).detach()
        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()

2.更新网络参数

这段choose_action函数是进行动作决策的代码。

在选择动作时,将当前状态输入神经网络,并输出所有的动作价值,然后以e的概率选择输出最大价值的动作,否则选择一个随机动作。

选择动作
    def choose_action(self,x):
        x = Variable(torch.unsqueeze(torch.FloatTensor(x),0))          #状态
        # print(x)
        if np.random.uniform() < Epsilon:                              #产生的随机数小于贪婪度,则选择神经网络预测的动作
            action_value = self.eval_net.forward(x)                    #在线网络
            action = torch.max(action_value, 1)[1].data.numpy()
            action = action[0] if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
            # print("1",action)
        else:                                                          #否则产生随机行为
            action = np.random.randint(0,N_actions)
            action = action if ENV_A_SHAPE == 0 else action.reshape(ENV_A_SHAPE)
            # print("2",action)
        # print(action)
        # exit(0)
        return action       

 这段store_transition函数是将样本存储在经验复用池中,

每一个样本的标签index=当前样本的个数(self.memory_counter)%经验复用池的大小(Memory_capacity),

也就是说,当样本的数量超过复用池大小的时候则从复用池的顶部开始覆盖。

    def store_transition(self,s,a,r,s_):
        transition = np.hstack((s,[a,r],s_))
        index = self.memory_counter % Memory_capacity
        self.memory[index,:] = transition
        self.memory_counter += 1

这段learn函数是获取了目标网络产生的Q值和在线网络产生的Q值,并用这两个值来训练online netwrok。

其中q_next,q_eval包含了所有动作的值,而需要的只是已经选择好的动作的值,其他并不需要,所以将其他的动作值全都变成0,将需要用到的动作的误差值反向传递回去,作为梯度更新,这就是最终想要达到的样子。

    def learn(self):
        #target net update
        if self.learn_step_counter % Target_replace_iter == 0:
            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 = Variable(torch.FloatTensor(b_memory[:,:N_states]))
        b_a = Variable(torch.LongTensor(b_memory[:,N_states:N_states+1].astype(int)))
        b_r = Variable(torch.FloatTensor(b_memory[:,N_states+1:N_states+2]))
        b_s_ = Variable(torch.FloatTensor(b_memory[:,-N_states:]))

        #计算q_target,loss,反向传递
        q_eval = self.eval_net(b_s).gather(1,b_a)
        q_next = self.target_net(b_s_).detach()
        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()

 这段类Net的功能就是搭建神经网络的代码,它搭建了两个结构完全一样的神经网络,其中online network的参数随着训练不停地更新,target network是online network的一个历史版本,拥有online network很久之前的一组参数,而且这组参数被暂时固定,训练一定次数之后再用online network的新参数来进行替换,而online network是在不断地被提升的,所以是一个可以被训练的神经网络。

参考以下资料:

小车立杆DQN实现理解

DQN强化学习

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DQN(Deep Q-Network)是一种深度强化学习算法,用于解决强化学习问题,特别是在小游戏等环境中。下面是一个简单的DQN实现游戏的代码讲解。 首先,我们需要导入相应的库: ```python import random import numpy as np from collections import deque from keras.models import Sequential from keras.layers import Dense from keras.optimizers import Adam ``` 然后,我们定义一个类来实现DQN算法: ```python class DQNAgent: def __init__(self, state_size, action_size): self.state_size = state_size self.action_size = action_size self.memory = deque(maxlen=2000) self.gamma = 0.95 # discount rate self.epsilon = 1.0 # exploration rate self.epsilon_decay = 0.995 self.epsilon_min = 0.01 self.learning_rate = 0.001 self.model = self._build_model() def _build_model(self): model = Sequential() model.add(Dense(24, input_dim=self.state_size, activation='relu')) model.add(Dense(24, activation='relu')) model.add(Dense(self.action_size, activation='linear')) model.compile(loss='mse', optimizer=Adam(lr=self.learning_rate)) return model def remember(self, state, action, reward, next_state, done): self.memory.append((state, action, reward, next_state, done)) def act(self, state): if np.random.rand() <= self.epsilon: return random.randrange(self.action_size) act_values = self.model.predict(state) return np.argmax(act_values[0]) def replay(self, batch_size): minibatch = random.sample(self.memory, batch_size) for state, action, reward, next_state, done in minibatch: target = reward if not done: target = reward + self.gamma * np.amax(self.model.predict(next_state)[0]) target_f = self.model.predict(state) target_f[0][action] = target self.model.fit(state, target_f, epochs=1, verbose=0) if self.epsilon > self.epsilon_min: self.epsilon *= self.epsilon_decay ``` 在上述代码中,我们定义了一个DQNAgent类,它包含了DQN算法的各种功能。主要有以下几个方法: - \_\_init\_\_:初始化方法,设置一些参数,建模型。 - \_build_model:构建神经网络模型。 - remember:将观察到的状态、动作、奖励、下一个状态和完成标志添加到记忆中。 - act:根据当前状态选择一个动作。 - replay:从记忆中随机采样一批数据并进行训练。 接下来,我们定义一个小游戏环境来测试我们的DQN算法: ```python class Game: def __init__(self): self.state_size = 4 self.action_size = 2 def get_state(self): # 返回当前状态 pass def take_action(self, action): # 执行动作并返回奖励、下一个状态和完成标志 pass def is_done(self): # 判断游戏是否结束 pass ``` 在Game类中,我们定义了一些游戏相关的方法,包括获取当前状态、执行动作并返回奖励和下一个状态、判断游戏是否结束等。 最后,我们可以使用以上定义的DQNAgent和Game类来训练和测试我们的DQN模型: ```python state_size = 4 action_size = 2 batch_size = 32 episodes = 1000 game = Game() agent = DQNAgent(state_size, action_size) for episode in range(episodes): state = game.get_state() for time in range(500): action = agent.act(state) reward, next_state, done = game.take_action(action) agent.remember(state, action, reward, next_state, done) state = next_state if done: break if len(agent.memory) > batch_size: agent.replay(batch_size) ``` 上述代码中,我们定义了一定数量的训练轮数(episodes),每轮训练将当前状态传递给DQNAgent进行动作选择并执行,然后将结果添加到记忆中,并进行一定数量的回放训练。训练完成后,我们可以使用训练好的模型进行测试。 这就是一个简单的DQN实现游戏的代码讲解。希望对你有所帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值