# Buggy code
def _noisy_layer(self, prefix, action_in, out_size, sigma0, non_linear=True):
    """
    a common dense layer: y = w^{T}x + b
    a noisy layer: y = (w + \\epsilon_w*\\sigma_w)^{T}x +
        (b+\\epsilon_b*\\sigma_b)
    where \epsilon are random variables sampled from factorized normal
    distributions and \\sigma are trainable variables which are expected to
    vanish along the training procedure
    """
    in_size = int(action_in.shape[1])

    epsilon_in = tf.random_normal(shape=[in_size])
    epsilon_out = tf.random_normal(shape=[out_size])
    epsilon_in = self._f_epsilon(epsilon_in)
    epsilon_out = self._f_epsilon(epsilon_out)
    epsilon_w = tf.matmul(
        a=tf.expand_dims(epsilon_in, -1), b=tf.expand_dims(epsilon_out, 0)
    )
    epsilon_b = epsilon_out
    sigma_w = tf.get_variable(
        name=prefix + "_sigma_w",
        shape=[in_size, out_size],
        dtype=tf.float32,
        initializer=tf.random_uniform_initializer(
            minval=-1.0 / np.sqrt(float(in_size)), maxval=1.0 / np.sqrt(float(in_size))
        ),
    )
    # TF noise generation can be unreliable on GPU
    # If generating the noise on the CPU,
    # lowering sigma0 to 0.1 may be helpful
    sigma_b = tf.get_variable(
        name=prefix + "_sigma_b",
        shape=[out_size],
        dtype=tf.float32,  # 0.5~GPU, 0.1~CPU
        initializer=tf.constant_initializer(sigma0 / np.sqrt(float(in_size))),
    )

    w = tf.get_variable(
        name=prefix + "_fc_w",
        shape=[in_size, out_size],
        dtype=tf.float32,
        initializer=tf.initializers.GlorotUniform(),
    )
    b = tf.get_variable(
        name=prefix + "_fc_b",
        shape=[out_size],
        dtype=tf.float32,
        initializer=tf.zeros_initializer(),
    )

    action_activation = tf.nn.xw_plus_b(
        action_in, w + sigma_w * epsilon_w, b + sigma_b * epsilon_b
    )

    if not non_linear:
        return action_activation
    return tf.nn.relu(action_activation)


# Traceback (AttributeError)
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/ray/tune/trial_runner.py", line 459, in _process_trial
result = self.trial_executor.fetch_result(trial)
File "/usr/local/lib/python3.7/site-packages/ray/tune/ray_trial_executor.py", line 377, in fetch_result
result = ray.get(trial_future[0], DEFAULT_GET_TIMEOUT)
File "/usr/local/lib/python3.7/site-packages/ray/worker.py", line 1504, in get
raise value.as_instanceof_cause()
ray.exceptions.RayTaskError(AttributeError): ray::DQN.__init__() (pid=96308, ip=192.168.120.74)
File "python/ray/_raylet.pyx", line 437, in ray._raylet.execute_task
File "python/ray/_raylet.pyx", line 449, in ray._raylet.execute_task
File "python/ray/_raylet.pyx", line 450, in ray._raylet.execute_task
File "python/ray/_raylet.pyx", line 452, in ray._raylet.execute_task
File "python/ray/_raylet.pyx", line 430, in ray._raylet.execute_task.function_executor
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/trainer_template.py", line 86, in __init__
Trainer.__init__(self, config, env, logger_creator)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/trainer.py", line 447, in __init__
super().__init__(config, logger_creator)
File "/usr/local/lib/python3.7/site-packages/ray/tune/trainable.py", line 172, in __init__
self._setup(copy.deepcopy(self.config))
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/trainer.py", line 591, in _setup
self._init(self.config, self.env_creator)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/trainer_template.py", line 105, in _init
self.config["num_workers"])
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/trainer.py", line 658, in _make_workers
logdir=self.logdir)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/evaluation/worker_set.py", line 60, in __init__
RolloutWorker, env_creator, policy, 0, self._local_config)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/evaluation/worker_set.py", line 262, in _make_worker
_fake_sampler=config.get("_fake_sampler", False))
File "/usr/local/lib/python3.7/site-packages/ray/rllib/evaluation/rollout_worker.py", line 355, in __init__
self._build_policy_map(policy_dict, policy_config)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/evaluation/rollout_worker.py", line 820, in _build_policy_map
policy_map[name] = cls(obs_space, act_space, merged_conf)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/policy/tf_policy_template.py", line 138, in __init__
obs_include_prev_action_reward=obs_include_prev_action_reward)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/policy/dynamic_tf_policy.py", line 137, in __init__
self.model = make_model(self, obs_space, action_space, config)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/dqn/dqn_policy.py", line 183, in build_q_model
parameter_noise=config["parameter_noise"])
File "/usr/local/lib/python3.7/site-packages/ray/rllib/models/catalog.py", line 349, in get_model_v2
name, **model_kwargs)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/dqn/distributional_q_model.py", line 185, in __init__
q_out = build_action_value_in_scope(self.model_out)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/dqn/distributional_q_model.py", line 178, in build_action_value_in_scope
return build_action_value(model_out)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/dqn/distributional_q_model.py", line 68, in build_action_value
"hidden_%d" % i, action_out, q_hiddens[i], sigma0)
File "/usr/local/lib/python3.7/site-packages/ray/rllib/agents/dqn/distributional_q_model.py", line 259, in _noisy_layer
initializer=tf.initializers.GlorotUniform())
File "/usr/local/lib/python3.7/site-packages/tensorflow_core/python/util/module_wrapper.py", line 193, in __getattr__
attr = getattr(self._tfmw_wrapped_module, name)
AttributeError: module 'tensorflow._api.v1.compat.v1.initializers' has no attribute 'GlorotUniform'

# Fixed code
def _noisy_layer(self, prefix, action_in, out_size, sigma0, non_linear=True):
    """
    a common dense layer: y = w^{T}x + b
    a noisy layer: y = (w + \\epsilon_w*\\sigma_w)^{T}x +
        (b+\\epsilon_b*\\sigma_b)
    where \epsilon are random variables sampled from factorized normal
    distributions and \\sigma are trainable variables which are expected to
    vanish along the training procedure
    """
    in_size = int(action_in.shape[1])

    epsilon_in = tf.random_normal(shape=[in_size])
    epsilon_out = tf.random_normal(shape=[out_size])
    epsilon_in = self._f_epsilon(epsilon_in)
    epsilon_out = self._f_epsilon(epsilon_out)
    epsilon_w = tf.matmul(
        a=tf.expand_dims(epsilon_in, -1), b=tf.expand_dims(epsilon_out, 0)
    )
    epsilon_b = epsilon_out
    sigma_w = tf.get_variable(
        name=prefix + "_sigma_w",
        shape=[in_size, out_size],
        dtype=tf.float32,
        initializer=tf.random_uniform_initializer(
            minval=-1.0 / np.sqrt(float(in_size)), maxval=1.0 / np.sqrt(float(in_size))
        ),
    )
    # TF noise generation can be unreliable on GPU
    # If generating the noise on the CPU,
    # lowering sigma0 to 0.1 may be helpful
    sigma_b = tf.get_variable(
        name=prefix + "_sigma_b",
        shape=[out_size],
        dtype=tf.float32,  # 0.5~GPU, 0.1~CPU
        initializer=tf.constant_initializer(sigma0 / np.sqrt(float(in_size))),
    )

    w = tf.get_variable(
        name=prefix + "_fc_w",
        shape=[in_size, out_size],
        dtype=tf.float32,
        initializer=tf.initializers.glorot_uniform(),
    )
    b = tf.get_variable(
        name=prefix + "_fc_b",
        shape=[out_size],
        dtype=tf.float32,
        initializer=tf.zeros_initializer(),
    )

    action_activation = tf.keras.layers.Lambda(
        lambda x: tf.matmul(x, w + sigma_w * epsilon_w) + b + sigma_b * epsilon_b
    )(action_in)

    if not non_linear:
        return action_activation
    return tf.nn.relu(action_activation)