XiangpengYang commited on
Commit
380cc0c
·
1 Parent(s): 1be271c

feat: select UR policy configuration

Browse files
Files changed (2) hide show
  1. model_loader.py +20 -9
  2. tests/test_model_loader.py +17 -7
model_loader.py CHANGED
@@ -14,6 +14,16 @@ from artifacts import (
14
  normalize_model_id,
15
  )
16
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  class ModelUnavailableError(RuntimeError):
19
  """Raised when the requested policy cannot be initialized."""
@@ -31,30 +41,31 @@ def _release_gpu_memory() -> None:
31
 
32
 
33
  class ModelManager:
34
- def __init__(self, loader: Callable[[str, str], object] | None = None):
35
  self._loader = loader or self._load_default
36
  self._lock = threading.Lock()
37
  self._value = None
38
- self._active_key: tuple[str, str] | None = None
39
  self._error: str | None = None
40
 
41
  @property
42
- def active_key(self) -> tuple[str, str] | None:
43
  return self._active_key
44
 
45
  @property
46
  def health_message(self) -> str:
47
  if self._value is not None and self._active_key is not None:
48
- model_id, checkpoint_path = self._active_key
49
- return f"Model ready: {model_id}/{checkpoint_path}."
50
  if self._error:
51
  return f"Model unavailable: {self._error}"
52
  return "Model has not been loaded yet."
53
 
54
- def get(self, model_id: str, checkpoint_path: str):
55
  key = (
56
  normalize_model_id(model_id),
57
  normalize_checkpoint_path(checkpoint_path),
 
58
  )
59
  if self._value is not None and self._active_key == key:
60
  return self._value
@@ -71,14 +82,14 @@ class ModelManager:
71
  except Exception as exc:
72
  _release_gpu_memory()
73
  detail = str(exc) or exc.__class__.__name__
74
- self._error = f"{key[0]}/{key[1]}: {detail}"
75
  raise ModelUnavailableError(self._error) from exc
76
  self._value = value
77
  self._active_key = key
78
  return value
79
 
80
  @staticmethod
81
- def _load_default(model_id: str, checkpoint_path: str):
82
  import torch
83
 
84
  if not torch.cuda.is_available():
@@ -90,7 +101,7 @@ class ModelManager:
90
  from openpi.training import config as openpi_config
91
 
92
  paths = download_checkpoint(model_id, checkpoint_path)
93
- config = openpi_config.get_config("pi05_ur_demo_state")
94
  return policy_config.create_trained_policy(
95
  config,
96
  paths.checkpoint,
 
14
  normalize_model_id,
15
  )
16
 
17
+ POLICY_CONFIGS = ("pi05_ur_demo_no_state", "pi05_ur_demo_state")
18
+ DEFAULT_POLICY_CONFIG = POLICY_CONFIGS[0]
19
+
20
+
21
+ def normalize_policy_config(value: str) -> str:
22
+ if value not in POLICY_CONFIGS:
23
+ choices = ", ".join(POLICY_CONFIGS)
24
+ raise ValueError(f"unsupported policy config {value!r}; choose one of: {choices}")
25
+ return value
26
+
27
 
28
  class ModelUnavailableError(RuntimeError):
29
  """Raised when the requested policy cannot be initialized."""
 
41
 
42
 
43
  class ModelManager:
44
+ def __init__(self, loader: Callable[[str, str, str], object] | None = None):
45
  self._loader = loader or self._load_default
46
  self._lock = threading.Lock()
47
  self._value = None
48
+ self._active_key: tuple[str, str, str] | None = None
49
  self._error: str | None = None
50
 
51
  @property
52
+ def active_key(self) -> tuple[str, str, str] | None:
53
  return self._active_key
54
 
55
  @property
56
  def health_message(self) -> str:
57
  if self._value is not None and self._active_key is not None:
58
+ model_id, checkpoint_path, config_name = self._active_key
59
+ return f"Model ready: {model_id}/{checkpoint_path} ({config_name})."
60
  if self._error:
61
  return f"Model unavailable: {self._error}"
62
  return "Model has not been loaded yet."
63
 
64
+ def get(self, model_id: str, checkpoint_path: str, config_name: str):
65
  key = (
66
  normalize_model_id(model_id),
67
  normalize_checkpoint_path(checkpoint_path),
68
+ normalize_policy_config(config_name),
69
  )
70
  if self._value is not None and self._active_key == key:
71
  return self._value
 
82
  except Exception as exc:
83
  _release_gpu_memory()
84
  detail = str(exc) or exc.__class__.__name__
85
+ self._error = f"{key[0]}/{key[1]} ({key[2]}): {detail}"
86
  raise ModelUnavailableError(self._error) from exc
87
  self._value = value
88
  self._active_key = key
89
  return value
90
 
91
  @staticmethod
92
+ def _load_default(model_id: str, checkpoint_path: str, config_name: str):
93
  import torch
94
 
95
  if not torch.cuda.is_available():
 
101
  from openpi.training import config as openpi_config
102
 
103
  paths = download_checkpoint(model_id, checkpoint_path)
104
+ config = openpi_config.get_config(config_name)
105
  return policy_config.create_trained_policy(
106
  config,
107
  paths.checkpoint,
tests/test_model_loader.py CHANGED
@@ -7,13 +7,16 @@ class ModelManagerTests(unittest.TestCase):
7
 
8
  calls = []
9
  manager = ModelManager(
10
- loader=lambda model, path: calls.append((model, path)) or object()
11
  )
12
- first = manager.get("owner/model", "a")
13
- self.assertIs(manager.get("owner/model", "a"), first)
14
- second = manager.get("owner/model", "b")
15
  self.assertIsNot(second, first)
16
- self.assertEqual(calls, [("owner/model", "a"), ("owner/model", "b")])
 
 
 
17
 
18
  def test_failed_load_is_reported_and_can_retry(self):
19
  from model_loader import ModelManager, ModelUnavailableError
@@ -28,7 +31,7 @@ class ModelManagerTests(unittest.TestCase):
28
  manager = ModelManager(loader=loader)
29
  for _ in range(2):
30
  with self.assertRaisesRegex(ModelUnavailableError, "bad checkpoint"):
31
- manager.get("owner/model", "a")
32
  self.assertEqual(attempts, 2)
33
  self.assertIn("bad checkpoint", manager.health_message)
34
 
@@ -37,7 +40,14 @@ class ModelManagerTests(unittest.TestCase):
37
 
38
  manager = ModelManager(loader=lambda *_: self.fail("loader was called"))
39
  with self.assertRaises(ValueError):
40
- manager.get("", "checkpoint")
 
 
 
 
 
 
 
41
 
42
 
43
  if __name__ == "__main__":
 
7
 
8
  calls = []
9
  manager = ModelManager(
10
+ loader=lambda model, path, config: calls.append((model, path, config)) or object()
11
  )
12
+ first = manager.get("owner/model", "a", "pi05_ur_demo_no_state")
13
+ self.assertIs(manager.get("owner/model", "a", "pi05_ur_demo_no_state"), first)
14
+ second = manager.get("owner/model", "a", "pi05_ur_demo_state")
15
  self.assertIsNot(second, first)
16
+ self.assertEqual(calls, [
17
+ ("owner/model", "a", "pi05_ur_demo_no_state"),
18
+ ("owner/model", "a", "pi05_ur_demo_state"),
19
+ ])
20
 
21
  def test_failed_load_is_reported_and_can_retry(self):
22
  from model_loader import ModelManager, ModelUnavailableError
 
31
  manager = ModelManager(loader=loader)
32
  for _ in range(2):
33
  with self.assertRaisesRegex(ModelUnavailableError, "bad checkpoint"):
34
+ manager.get("owner/model", "a", "pi05_ur_demo_no_state")
35
  self.assertEqual(attempts, 2)
36
  self.assertIn("bad checkpoint", manager.health_message)
37
 
 
40
 
41
  manager = ModelManager(loader=lambda *_: self.fail("loader was called"))
42
  with self.assertRaises(ValueError):
43
+ manager.get("", "checkpoint", "pi05_ur_demo_no_state")
44
+
45
+ def test_unsupported_policy_config_is_rejected_before_loader(self):
46
+ from model_loader import ModelManager
47
+
48
+ manager = ModelManager(loader=lambda *_: self.fail("loader was called"))
49
+ with self.assertRaisesRegex(ValueError, "unsupported policy config"):
50
+ manager.get("owner/model", "checkpoint", "pi05_libero")
51
 
52
 
53
  if __name__ == "__main__":