code: def __init__(self, config):
      self.config = config
  
      self.sample_data_queue = queue.Queue()
      self.batch_buffer = defaultdict(list)
  
      # =========== Create Agent ==========
      env = gym.make(config["env_name"])
      env = wrap_deepmind(env, dim=config["env_dim"], obs_format="NCHW")
      obs_shape = env.observation_space.shape
      act_dim = env.action_space.n
  
      self.config["obs_shape"] = obs_shape
      self.config["act_dim"] = act_dim
  
      model = AtariModel(act_dim)
      algorithm = parl.algorithms.A3C(
          model, vf_loss_coeff=config["vf_loss_coeff"]
      )
      self.agent = AtariAgent(
          algorithm,
          obs_shape=self.config["obs_shape"],
          predict_thread_num=self.config["predict_thread_num"],
          learn_data_provider=self.learn_data_provider,
      )
  
      if machine_info.is_gpu_available():
          assert (
              get_gpu_count() == 1
          ), "Only support training in single GPU,\
                      Please set environment variable: `export CUDA_VISIBLE_DEVICES=[GPU_ID_YOU_WANT_TO_USE]` ."
  
      else:
          cpu_num = os.environ.get("CPU_NUM")
          assert (
              cpu_num is not None and cpu_num == "1"
          ), "Only support training in single CPU,\
                      Please set environment variable:  `export CPU_NUM=1`."
  
      # ========== Learner ==========
      self.lr, self.entropy_coeff = None, None
      self.lr_scheduler = PiecewiseScheduler(config["lr_scheduler"])
      self.entropy_coeff_scheduler = PiecewiseScheduler(
          config["entropy_coeff_scheduler"]
      )
  
      self.total_loss_stat = WindowStat(100)
      self.pi_loss_stat = WindowStat(100)
      self.vf_loss_stat = WindowStat(100)
      self.entropy_stat = WindowStat(100)
  
      self.learn_time_stat = TimeStat(100)
      self.start_time = None
  
      # learn thread
      self.learn_thread = threading.Thread(target=self.run_learn)
      self.learn_thread.setDaemon(True)
      self.learn_thread.start()
  
      self.predict_input_queue = queue.Queue()
  
      # predict thread
      self.predict_threads = []
      for i in six.moves.range(self.config["predict_thread_num"]):
          predict_thread = threading.Thread(
              target=self.run_predict, args=(i,)
          )
          predict_thread.setDaemon(True)
          predict_thread.start()
          self.predict_threads.append(predict_thread)
  
      # ========== Remote Simulator ===========
      self.remote_count = 0
  
      self.remote_metrics_queue = queue.Queue()
      self.sample_total_steps = 0
  
      self.create_actors()
  
imports: from parl.utils import check_version_for_fluid
  import gym
  import numpy
  import os
  from six.moves import queue
  import six
  import time
  import threading
  import parl
  from atari_model import AtariModel
  from atari_agent import AtariAgent
  from collections import defaultdict
  from parl.env.atari_wrappers import wrap_deepmind
  from parl.utils import logger, get_gpu_count, summary
  from parl.utils.scheduler import PiecewiseScheduler
  from parl.utils.time_stat import TimeStat
  from parl.utils.window_stat import WindowStat
  from parl.utils.rl_utils import calc_gae
  from parl.utils import machine_info
  from actor import Actor
label_desc: Use image node_id 1 to create a new Learner object from inherited base classes: object with example: obj = Learner(config)