class_docstr: Worker class for distributional running
class_docstr_tok: ["Worker","class","for","distributional","running"]
docstr: Define a worker
  :return: None
docstr_tok: ["Define","a","worker",":","return",":","None"]
code: def work(self):
      """
      Define a worker
      :return: None
      """
      global GLOBAL_EP, GLOBAL_RUNNING_R, GLOBAL_UPDATE_COUNTER
      while not COORD.should_stop():
          s = self.env.reset()
          ep_r = 0
          buffer_s, buffer_a, buffer_r = [], [], []
          for t in range(MAX_STEPS):
              if (
                  not ROLLING_EVENT.is_set()
              ):  # while global PPO is updating
                  ROLLING_EVENT.wait()  # wait until PPO is updated
                  buffer_s, buffer_a, buffer_r = (
                      [],
                      [],
                      [],
                  )  # clear history buffer, use new policy to collect data
              a = self.ppo.get_action(s)
              s_, r, done, _ = self.env.step(a)
              if RENDER and self.wid == 0:
                  self.env.render()
              buffer_s.append(s)
              buffer_a.append(a)
              buffer_r.append(r)
              s = s_
              ep_r += r
  
              GLOBAL_UPDATE_COUNTER += 1  # count to minimum batch size, no need to wait other workers
              if (
                  t == MAX_STEPS - 1
                  or GLOBAL_UPDATE_COUNTER >= MIN_BATCH_SIZE
              ):
                  # finish patyh
                  if done:
                      v_s_ = 0
                  else:
                      v_s_ = self.ppo.critic(
                          np.array([s_], np.float32)
                      )[0][0]
                  discounted_r = []  # compute discounted reward
                  for r in buffer_r[::-1]:
                      v_s_ = r + GAMMA * v_s_
                      discounted_r.append(v_s_)
                  discounted_r.reverse()
                  buffer_r = np.array(discounted_r)[:, np.newaxis]
                  QUEUE.put(
                      [buffer_s, buffer_a, buffer_r]
                  )  # put data in the queue
                  buffer_s, buffer_a, buffer_r = [], [], []
  
                  # update
                  if GLOBAL_UPDATE_COUNTER >= MIN_BATCH_SIZE:
                      ROLLING_EVENT.clear()  # stop collecting data
                      UPDATE_EVENT.set()  # globalPPO update
  
                  # stop training
                  if GLOBAL_EP >= TRAIN_EPISODES:
                      COORD.request_stop()
                      break
  
          print(
              "Training  | Episode: {}/{}  | Worker: {} | Episode Reward: {:.4f}  | Running Time: {:.4f}".format(
                  GLOBAL_EP + 1,
                  TRAIN_EPISODES,
                  self.wid,
                  ep_r,
                  time.time() - T0,
              )
          )
          # record reward changes, plot later
          if len(GLOBAL_RUNNING_R) == 0:
              GLOBAL_RUNNING_R.append(ep_r)
          else:
              GLOBAL_RUNNING_R.append(
                  GLOBAL_RUNNING_R[-1] * 0.9 + ep_r * 0.1
              )
          GLOBAL_EP += 1
  
imports: import argparse
  import os
  import queue
  import threading
  import time
  import gym
  import matplotlib.pyplot
  import numpy
  import tensorflow
  import tensorflow_probability
  import tensorlayer
label_desc: Use image node_id 2 for calling the Worker obj's underlying member method code with example usage: obj.work() without return types