Repository: ray-project/ray

Issue:
Undefined Reference To "run_identifier" on GPU Machine With tune.Experiment
On the latest nightly build, passing a `tune.Experiment` into `tune.Run` on a GPU machine results in an undefined reference to `run_identifier`.  This occurs because `run_identifier` is defined conditionally [here](https://github.com/ray-project/ray/blob/91acecc9f9eb8d1a7e9fe651bd50e3b2d68ecee2/python/ray/tune/tune.py#L214). The `run_identifier` reference occurs on [this line](https://github.com/ray-project/ray/blob/91acecc9f9eb8d1a7e9fe651bd50e3b2d68ecee2/python/ray/tune/tune.py#L268).

Traceback for the error:
```
2019-10-22 06:57:15,904 DEBUG registry.py:59 -- Detected class for trainable.
2019-10-22 06:57:15,906 DEBUG tune.py:236 -- Ignoring some parameters passed into tune.run.
2019-10-22 06:57:15,909 DEBUG trial_runner.py:175 -- Starting a new experiment.
Traceback (most recent call last):
  File "/home/steven/res/railrl-private/railrl/launchers/ray/local_launch.py", line 94, in <module>
    launch_local_experiment(**local_launch_variant)
  File "/home/steven/res/railrl-private/railrl/launchers/ray/local_launch.py", line 82, in launch_local_experiment
    queue_trials=True,
  File "/env/lib/python3.5/site-packages/ray/tune/tune.py", line 268, in run
    elif _check_default_resources_override(run_identifier):
UnboundLocalError: local variable 'run_identifier' referenced before assignment
```


Discussion:

Resolving patch:
diff --git a/python/ray/tune/experiment.py b/python/ray/tune/experiment.py
--- a/python/ray/tune/experiment.py
+++ b/python/ray/tune/experiment.py
@@ -102,9 +102,9 @@ def __init__(self,
                     "criteria must take exactly 2 parameters.".format(stop))
 
         config = config or {}
-        run_identifier = Experiment._register_if_needed(run)
+        self._run_identifier = Experiment._register_if_needed(run)
         spec = {
-            "run": run_identifier,
+            "run": self._run_identifier,
             "stop": stop,
             "config": config,
             "resources_per_trial": resources_per_trial,
@@ -125,7 +125,7 @@ def __init__(self,
             if restore else None
         }
 
-        self.name = name or run_identifier
+        self.name = name or self._run_identifier
         self.spec = spec
 
     @classmethod
@@ -202,6 +202,11 @@ def remote_checkpoint_dir(self):
         if self.spec["upload_dir"]:
             return os.path.join(self.spec["upload_dir"], self.name)
 
+    @property
+    def run_identifier(self):
+        """Returns a string representing the trainable identifier."""
+        return self._run_identifier
+
 
 def convert_to_experiment_list(experiments):
     """Produces a list of Experiment objects.
diff --git a/python/ray/tune/tune.py b/python/ray/tune/tune.py
--- a/python/ray/tune/tune.py
+++ b/python/ray/tune/tune.py
@@ -4,6 +4,7 @@
 
 import logging
 import time
+import six
 
 from ray.tune.error import TuneError
 from ray.tune.experiment import convert_to_experiment_list, Experiment
@@ -45,6 +46,9 @@ def _make_scheduler(args):
 
 
 def _check_default_resources_override(run_identifier):
+    if not isinstance(run_identifier, six.string_types):
+        # If obscure dtype, assume it is overriden.
+        return True
     trainable_cls = get_trainable_cls(run_identifier)
     return hasattr(trainable_cls, "default_resource_request") and (
         trainable_cls.default_resource_request.__code__ !=
@@ -265,7 +269,7 @@ def run(run_or_experiment,
                       dict) and "gpu" in resources_per_trial:
             # "gpu" is manually set.
             pass
-        elif _check_default_resources_override(run_identifier):
+        elif _check_default_resources_override(experiment.run_identifier):
             # "default_resources" is manually overriden.
             pass
         else:


Test patch: