您需要为 Q 学习实现的神经网络必须逼近 Q 函数Q(s,a). 有两种方法可以做到这一点:
使用(s,a)作为输入。为简单起见,许多文献都会假设这一点,您会看到如下符号q^(s,a,θ)显示你正在逼近函数,并有参数θ学习神经网络。
使用(s)作为输入,并有多个网络输出Q(s,a)values - 每个可能的操作都有一个。例如,如果您有四个可能的操作,那么您的输出可能是[q^0,q^1,q^2,q^3]. 这可能更有效,因为为了找到最佳、最大化的动作,您需要计算所有动作值。
一旦你建立了这样的神经网络,以及一个历史表(随着实际采取的每一个动作而增长),这就是你如何使用它的方式:
For each sampled [state, action, reward, future_state]:
Calculate td_target = reward + gamma * max_a'(Q(future_state, a')):
Run NN(future_state, a') forward for each possible action a' and find max
Train the NN using the inputs (state, action) and desired output td_target
如果网络一次输出多个 Q 值,您将使用此变体:
For each sampled [state, action, reward, future_state]:
Calculate td_target = reward + gamma * max_a'(Q(future_state, a')):
Run the NN(future_state) forward and take the max output
Construct the desired output:
Run the NN(state) forward to get array e.g. [q0, q1, q2, q3]
Substitute td_target depending on action e.g. [q0, q1, td_target, q3]
Train the NN using the inputs (state) to learn the desired output
尽管第二种方法看起来更复杂,但它避免了在多个a'值上循环(或小批量)来找到最大值,因此效率更高。
如果您使用 NN 的冻结副本来帮助提高稳定性(DQN 中的一个常见功能),那么您应该专门使用冻结副本来计算 TD 目标,并使用学习副本来计算当前输出。
请注意,不要存储,而是始终重新计算 Q 值,这一点很重要。这既是因为初始值将不正确(取决于 NN 的初始化方式),而且随着代理学习更好的策略,它们应该随着时间的推移而改进。
另一个重要的细节是你不应该使用 NN 来计算终端状态的 Q 值。如果future_state是终端,则不使用 NN,而是将其max_a'(Q(future_state, a'))视为零。通常只是检测到这是一个终端状态并以0某种方式对其进行硬编码。