def train(self, sample_buffer, print_every=500):
        """ add new samples in sample_buffer to replay buffer and train
        do not keep hidden state (split episode into short sequences)

        Parameters
        ----------
        sample_buffer: magent.utility.EpisodesBuffer
            buffer contains samples
        print_every: int
            print log every print_every batches

        Returns
        -------
        loss: float
            bellman residual loss
        value: float
            estimated state value
        """
        add_num = self._add_to_replay_buffer(sample_buffer)

        batch_size = self.batch_size
        unroll_step = self.unroll_step

        # calc sample weight of episodes (i.e. their lengths)
        replay_buffer = self.replay_buffer
        replay_lens_sum = np.sum(self.replay_buffer_lens)
        weight = np.array(self.replay_buffer_lens, dtype=np.float32) / replay_lens_sum

        n_batches = self.train_freq * add_num / (batch_size * (unroll_step - self.skip_error))
        if n_batches == 0:
            return 0, 0

        max_ = batch_size * unroll_step
        batch_view = np.zeros((max_+1,) + self.view_space, dtype=np.float32)
        batch_feature = np.zeros((max_+1,) + self.feature_space, dtype=np.float32)
        batch_action = np.zeros((max_,), dtype=np.int32)
        batch_reward = np.zeros((max_,), dtype=np.float32)
        batch_terminal = np.zeros((max_,), dtype=np.bool)
        batch_mask = np.zeros((max_,), dtype=np.float32)

        # calc batch number
        n_batches = int(self.train_freq * add_num / (batch_size * (unroll_step - self.skip_error)))
        print("batches: %d  add: %d  replay_len: %d/%d" %
              (n_batches, add_num, len(self.replay_buffer), self.memory_size))

        ct = 0
        total_loss = 0
        start_time = time.time()
        # train batches
        for i in range(n_batches):
            indexes = np.random.choice(len(replay_buffer), self.batch_size, p=weight)

            batch_mask[:] = 0

            for j in range(batch_size):
                item = replay_buffer[indexes[j]]
                v, f, a, r, t = item[0], item[1], item[2], item[3], item[4]
                length = len(v)

                start = np.random.randint(length)
                real_step = min(length - start, unroll_step)

                beg = j * unroll_step
                batch_view[beg:beg+real_step]     = v[start:start+real_step]
                batch_feature[beg:beg+real_step]  = f[start:start+real_step]
                batch_action[beg:beg+real_step]   = a[start:start+real_step]
                batch_reward[beg:beg+real_step]   = r[start:start+real_step]
                batch_terminal[beg:beg+real_step] = t[start:start+real_step]
                batch_mask[beg:beg+real_step]     = 1.0

                if not t[start+real_step-1]:
                    batch_mask[beg+real_step-1] = 0

            # collect trajectories from different IDs to a single buffer
            target = self._calc_target(batch_view[1:], batch_feature[1:],
                                       batch_reward, batch_terminal, batch_size, unroll_step)

            ret = self.sess.run([self.train_op, self.loss], feed_dict={
                self.input_view:      batch_view[:-1],
                self.input_feature:   batch_feature[:-1],
                self.action:          batch_action,
                self.target:          target,
                self.mask:            batch_mask,
                self.batch_size_ph:   batch_size,
                self.unroll_step_ph:  unroll_step,
            })
            loss = ret[1]
            total_loss += loss

            if ct % self.target_update == 0:
                self.sess.run(self.update_target_op)

            if ct % print_every == 0:
                print("batch %5d, loss %.6f, qvalue %.6f" % (ct, loss, self._eval(target)))
            ct += 1
            self.train_ct += 1

        total_time = time.time() - start_time
        step_average = total_time / max(1.0, (ct / 1000.0))
        print("batches: %d,  total time: %.2f,  1k average: %.2f" % (ct, total_time, step_average))

        return total_loss / ct if ct != 0 else 0, self._eval(target)
 add new samples in sample_buffer to replay buffer and train
        do not keep hidden state (split episode into short sequences)

        Parameters
        ----------
        sample_buffer: magent.utility.EpisodesBuffer
            buffer contains samples
        print_every: int
            print log every print_every batches

        Returns
        -------
        loss: float
            bellman residual loss
        value: float
            estimated state value
        
python/magent/builtin/tf_model/drqn.py