[Deep Q-Network]Tensorflow自动微分时如何排除ops

[Deep Q-Network]How to exclude ops at auto-differential of Tensorflow

我正在尝试使用 Tensorflow 创建类似于 Deepmind DQN3.0 的深度 Q 网络 (DQN),但我遇到了一些困难。我认为原因是 TensorFlow 的自动微分方法。

请看这张照片。这是DQN3.0的架构

在监督学习中,为了让网络的输出逼近到标签,通过损失函数计算差值,反向传播,用优化器更新参数。

在DQN中,AI过去经历过的状态积累在记忆中,再次输入到TergetNetwork和Network这两个神经网络,两个网络的差异体现在Network中。

每个网络的输出不是总数为1的概率而是期望值。 TergetNetwork 的输出将包括折扣率(gamma) 和当时获得的奖励。

并且,看DQN 3.0(lua + torch)的实现,它将当前网络的输出与当时选择的action进行比较,通过backward方法直接向后传播差异.

function nql:getQUpdate(args)
    local s, a, r, s2, term, delta
    local q, q2, q2_max

    s = args.s
    a = args.a
    r = args.r
    s2 = args.s2
    term = args.term

    -- The order of calls to forward is a bit odd in order
    -- to avoid unnecessary calls (we only need 2).

    -- delta = r + (1-terminal) * gamma * max_a Q(s2, a) - Q(s, a)
    term = term:clone():float():mul(-1):add(1)

    local target_q_net
    if self.target_q then
        target_q_net = self.target_network
    else
        target_q_net = self.network
    end

    -- Compute max_a Q(s_2, a).
    q2_max = target_q_net:forward(s2):float():max(2)

    -- Compute q2 = (1-terminal) * gamma * max_a Q(s2, a)
    q2 = q2_max:clone():mul(self.discount):cmul(term)

    delta = r:clone():float()

    if self.rescale_r then
        delta:div(self.r_max)
    end
    delta:add(q2)

    -- q = Q(s,a)
    local q_all = self.network:forward(s):float()
    q = torch.FloatTensor(q_all:size(1))
    for i=1,q_all:size(1) do
        q[i] = q_all[i][a[i]]
    end
    delta:add(-1, q)

    if self.clip_delta then
        delta[delta:ge(self.clip_delta)] = self.clip_delta
        delta[delta:le(-self.clip_delta)] = -self.clip_delta
    end

    local targets = torch.zeros(self.minibatch_size, self.n_actions):float()
    for i=1,math.min(self.minibatch_size,a:size(1)) do
        targets[i][a[i]] = delta[i]
    end

    if self.gpu >= 0 then targets = targets:cuda() end

    return targets, delta, q2_max
end


function nql:qLearnMinibatch()
    -- Perform a minibatch Q-learning update:
    -- w += alpha * (r + gamma max Q(s2,a2) - Q(s,a)) * dQ(s,a)/dw
    assert(self.transitions:size() > self.minibatch_size)

    local s, a, r, s2, term = self.transitions:sample(self.minibatch_size)

    local targets, delta, q2_max = self:getQUpdate{s=s, a=a, r=r, s2=s2,
    term=term, update_qmax=true}

    -- zero gradients of parameters
    self.dw:zero()

    -- get new gradient
    self.network:backward(s, targets)

因此,如果你不介意上图中的计算块的速度,你可以在CPU上使用Numpy等计算,而不是使用Tensorflow,我可以排除我在想它来自自动微分。

在 DQN3.0 中,仅从 Network(蓝色)的输出层计算反向传播。但是,对于我在 Tensorflow 中的模型,它从最终操作 mul.

开始

我想使用 Tensorflow 从与 DQN3.0 中相同的输出层开始反向传播。

我知道我可以使用 compute_gradients() 优化器方法和 运行 从头开始​​创建的手动微分过程来获得 grads_and_vars。但是,我认为实现这样一个卷积层的差异对我来说是非常困难的。

我可以使用 Tensorflow 函数或其他方法在自动微分时排除计算块操作吗?还是有其他方法可以解决?

你问的问题与训练你的网络不兼容。

反向传播起点是您的损失函数(a.k.a 红色块)。在这个损失函数中,所有可以微分的操作都会,这样梯度就可以"flow"通过网络。您在此过程中 "exclude" 的每个操作(例如使用 tf.stop_gradient)都将成为反向传播的停止点,并且梯度不会流向您的操作所依赖的每个值。

基本上是什么意思?如果排除 "compute block",则无法计算任何变量的梯度。

谢谢大家

我暂时解决了排除问题

我创建了修改 tf.gradients 函数的原始函数,如下所示。

def gradients(ys,
          xs,
          grad_start, #***** ←Add arguments that new gradient start op ******
          grad_ys=None,
          name="gradients",
          colocate_gradients_with_ops=False,
          gate_gradients=False,
          aggregation_method=None):
              .
              .
              .
          # The set of 'from_ops'.
          stop_ops = _StopOps(from_ops, pending_count)
          while queue:
            # generate gradient subgraph for op.
            op = queue.popleft()
            with _maybe_colocate_with(op, colocate_gradients_with_ops):
              if loop_state:
                loop_state.EnterGradWhileContext(op, before=True)
              out_grads = _AggregatedGrads(grads, op, loop_state, aggregation_method)
              if loop_state:
                loop_state.ExitGradWhileContext(op, before=True)

              #*************************************************************
              # Add 2 line that replace 'out_grads' op to new grad start op
              if grad_start is not None and op == grad_start.op:
                  out_grads = ys
              .
              .
              .

正如我用 Tensorboard 确认的那样,它看起来符合预期。 https://i.stack.imgur.com/vG1e0.png