本文主要是介绍pytorch强化学习(2)——重写DQN,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
思路
在q-learning当中,Q函数的输入是状态state和action,输出是q-value。
而DQN就是使用神经网络来拟合Q函数,所以从直观上来说,我觉得神经网络的输入应该是状态state和action,输出应该是q-value。
但是,网上绝大多数DQN的代码实现都把state作为网络输入,把所有action的q-value的组合作为网络输出。我觉得这是不直观的、令人费解的,于是我按照自己的想法写了一份DQN代码。
在下面的代码中,神经网络的输入是state和action的连接,若干个浮点数表示state,一个整数表示action。神经网络的输出只有一个元素,代表q-value的值。
代码
env.py
import gym
from DQN_brain import DQN
import matplotlib.pyplot as plt
import numpylr = 1e-3 # 学习率
gamma = 0.9 # 折扣因子
epsilon = 0.9 # 贪心系数
n_hidden = 50 # 隐含层神经元个数env = gym.make("CartPole-v1")
n_states = env.observation_space.shape[0] # 4
n_actions = env.action_space.n # 2 动作的个数dqn = DQN(n_states, n_hidden, n_actions, lr, gamma, epsilon)if __name__ == '__main__':reward_list = []for i in range(100):# 获取初始环境state = env.reset()[0] # len=4total_reward = 0done = Falsewhile True:# 获取最优动作action = dqn.optimal_action(state)# 有一定概率不采取最优动作,而是随机选择一个动作执行,这一点很重要if numpy.random.random() > epsilon:action = numpy.random.randint(n_actions)# 更新环境next_state, reward, done, _, _ = env.step(action)dqn.learning(state, next_state, action, reward, done)# 更新一些变量state = next_statetotal_reward += rewardif done:breakprint("第%d回合,total_reward=%f" % (i, total_reward))reward_list.append(total_reward)# 绘图episodes_list = list(range(len(reward_list)))plt.plot(episodes_list, reward_list)plt.xlabel('Episodes')plt.ylabel('Returns')plt.title('DQN Returns')plt.show()
DQN_brain.py
import torch
from torch import nn, Tensorclass Net(nn.Module):# 构造有2个隐含层的网络def __init__(self, input_dim: int, n_hidden: int, output_dim: int):super().__init__()self.network = nn.Sequential(torch.nn.Linear(input_dim, n_hidden, dtype=torch.float),torch.nn.ReLU(),torch.nn.Linear(n_hidden, n_hidden, dtype=torch.float),torch.nn.ReLU(),torch.nn.Linear(n_hidden, n_hidden, dtype=torch.float),torch.nn.ReLU(),torch.nn.Linear(n_hidden, output_dim, dtype=torch.float),)# 前传,直接调用Net对象,其实就是调用forward函数def forward(self, x): # [b,n_states]return self.network(x)class DQN:def __init__(self, n_states: int, n_hidden: int, n_actions: int, lr: float, gamma: float, epsilon: float):# 属性分配self.n_states = n_states # 状态的特征数self.n_hidden = n_hidden # 隐含层个数self.n_actions = n_actions # 动作数self.lr = lr # 训练时的学习率self.gamma = gamma # 折扣因子,对下一状态的回报的缩放self.epsilon = epsilon # 贪婪策略,有1-epsilon的概率探索# 实例化训练网络,网络的输入是state+action,# 网络的输出是只有一个元素的一维向量,代表该动作在该状态下的q-valueself.q_net = Net(self.n_states + 1, self.n_hidden, 1)# 优化器,更新训练网络的参数self.q_optimizer = torch.optim.Adam(self.q_net.parameters(), lr=lr)self.criterion = torch.nn.MSELoss() # 损失函数# 把状态和动作转化为tensor并连接起来def _concat_input(self, state: list[float], action: int):state_tensor = torch.tensor(state, dtype=torch.float)action_tensor = torch.tensor([action], dtype=torch.float)return torch.concat([state_tensor, action_tensor])# 获取q-value值最大的actiondef optimal_action(self, state: list[float]):q_values = torch.tensor([], dtype=torch.float)# 获取所有action的q-valuefor action in range(self.n_actions):q_values = torch.concat([q_values, self.get_q_value(state, action)])# 返回值最大的那个下标,item()函数只能对只有单个元素的tensor使用return torch.argmax(q_values).item()# 更新网络def learning(self,state: list[float],next_state: list[float],action: int,reward: float,done: bool) -> None:# 下一状态的最优动作next_optimal_action = self.optimal_action(next_state)# 当前状态q_valueq_value = self.get_q_value(state, action)# 下一状态q_valuenext_q_value = self.get_q_value(next_state, next_optimal_action)# q_target计算q_target = reward + self.gamma * next_q_value * (1. - float(done))# 计算loss,然后反向传播,然后梯度下降loss: Tensor = self.criterion(q_value, q_target)self.q_optimizer.zero_grad()loss.backward()self.q_optimizer.step()# 根据状态和动作获取q_valuedef get_q_value(self, state: list[float], action: int) -> Tensor:return self.q_net(self._concat_input(state, action))# tensor([5.5241], grad_fn=<ViewBackward0>)
这篇关于pytorch强化学习(2)——重写DQN的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!