我正在训练一个DQN来播放OpenAI的Atari环境,但是我的网络的Q值很快就爆炸了,远远超出了实际情况。
下面是代码的相关部分:

for state, action, reward, next_state, done in minibatch:
        if not done:
            # To save on memory, next_state is just one frame
            # So we have to add it to the current state to get the actual input for the network
            next_4_states = np.array(state)
            next_4_states = np.roll(next_4_states, 1, axis=3)
            next_4_states[:, :, :, 0] = next_state
            target = reward + self.gamma * \
                np.amax(self.target_model.predict(next_4_states))
        else:
            target = reward
        target_f = self.target_model.predict(state)
        target_f[0][action] = target

        self.target_model.fit(state, target_f, epochs=1, verbose=0)

贴现因子为0.99(贴现因子为0.9时不会发生这种情况,但也不会收敛,因为它无法提前思考足够远)。
在代码中,发生这种情况的原因是所有不需要更新的Q值(对于我们没有采取的操作)都略有增加。我的理解是,在训练期间将网络自身的输出传递给网络应该保持输出不变,而不是增加或减少输出。我的模型有问题吗?有什么方法可以屏蔽更新,使其只更新相关的Q值吗?
编辑:我的模型创建代码在这里:
def create_model(self, input_shape, num_actions, learning_rate):
        model = Sequential()
        model.add(Convolution2D(32, 8, strides=(4, 4),
                                activation='relu', input_shape=(input_shape)))
        model.add(Convolution2D(64, 4, strides=(2, 2), activation='relu'))
        model.add(Convolution2D(64, 3, strides=(1, 1), activation='relu'))
        model.add(Flatten())
        model.add(Dense(512, activation='relu'))
        model.add(Dense(num_actions))

        model.compile(loss='mse', optimizer=Adam(lr=learning_rate))

        return model

我创造了其中两个。一个用于在线网络,一个用于目标。

最佳答案

哪些预测得到更新?
在代码中,发生这种情况的原因是所有不需要更新的Q值(对于我们没有采取的操作)都略有增加。我的理解是,在训练期间将网络自身的输出传递给网络应该保持输出不变,而不是增加或减少输出。
下面我画了一个非常简单的神经网络,有3个输入节点,3个隐藏节点和3个输出节点。假设您只为第一个动作设置了一个新的目标,并且简单地使用现有的预测作为其他操作的目标。这只会导致第一个操作/输出出现非零(为简单起见,我假设大于零)错误(在图像中用delta表示),其他操作/输出出现0错误。
我已经用粗体画出了这个错误从输出传播到隐藏层的连接。请注意隐藏层中的每个节点仍然会得到错误。当这些节点将错误传播回输入层时,它们将通过输入层和隐藏层之间的所有连接执行此操作,因此可以修改所有这些权重。
所以,想象一下所有的权重都更新了,现在想象一下用原始输入做一个新的前锋传球。您是否希望输出节点2和3具有与以前完全相同的输出?不,可能不是;从隐藏节点到最后两个输出的连接可能仍然具有相同的权重,但所有三个隐藏节点都将具有不同的激活级别。所以不,其他输出不能保证保持不变。
python - 训练DQN时Q值爆炸-LMLPHP
有什么方法可以屏蔽更新,使其只更新相关的Q值吗?
不容易不,如果有的话。问题是除了最后一对层之间的连接之外,其他层对之间的连接不是特定于操作的,我认为您也不希望它们是特定的。
目标网络
我的模型有问题吗?
我看到的一件事是,你似乎正在更新用于生成目标的同一个网络:

target_f = self.target_model.predict(state)


self.target_model.fit(state, target_f, epochs=1, verbose=0)

两者都使用self.target_model。您应该为这两条线路使用单独的网络副本,并且只有在较长的时间段之后,才能将更新后的网络权重复制到用于计算目标的网络中。有关更多信息,请参见this post中的添加3。
双DQN
除此之外,众所周知,DQN仍然有可能高估Q值(尽管它通常不应该完全爆炸)。这可以通过使用Double DQN来解决(注意:这是稍后在DQN之上添加的改进)。

10-07 20:24