Skip to content

Commit 6a9600b

Browse files
authored
update torchserve and streamlit (#15)
1 parent 91b993b commit 6a9600b

File tree

6 files changed

+54
-31
lines changed

6 files changed

+54
-31
lines changed

README.md

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
# Torchserve Dashboard
2+
[![Total Downloads](https://pepy.tech/badge/torchserve-dashboard)](https://pepy.tech/project/torchserve-dashboard)
3+
![](https://img.shields.io/pypi/dm/torchserve-dashboard)
4+
25

36
Torchserve Dashboard using Streamlit
47

@@ -8,7 +11,7 @@ Related blog [post](https://cceyda.github.io/blog/torchserve/streamlit/dashboard
811

912
# Usage
1013
Additional Requirement:
11-
[torchserve](https://github.com/pytorch/serve/tree/v0.3.1#install-torchserve-and-torch-model-archiver) (recommended:v0.3.1)
14+
[torchserve](https://github.com/pytorch/serve/tree/v0.5.0#install-torchserve-and-torch-model-archiver) (recommended:v0.5.0)
1215

1316
Simply run:
1417

@@ -22,7 +25,7 @@ torchserve-dashboard --server.port 8105 -- --config_path ./torchserve.properties
2225
torchserve-dashboard -- --config_path ./torchserve.properties --model_store ./model_store
2326
```
2427

25-
:exclamation: Keep in mind that If you change any of the `--config_path`,`--model_store`,`--metrics_location`,`--log_location` options while there is a torchserver already running before starting torch-dashboard they won't come into effect until you stop&start torchserve.
28+
:exclamation: Keep in mind that If you change any of the `--config_path`,`--model_store`,`--metrics_location`,`--log_location` options while there is a torchserver already running before starting torch-dashboard they won't come into effect until you stop&start torchserve. These options are used instead of their respective environment variables `TS_CONFIG_FILE, METRICS_LOCATION, LOG_LOCATION`.
2629

2730
OR
2831
```bash
@@ -56,6 +59,8 @@ If the server doesn't start for some reason check if your ports are already in u
5659

5760
[31-may-2021] Update to v0.4 (Add workflow API) Refactor out streamlit from api.py.
5861

62+
[30-nov-2021] Update to v0.5, adding support for [encrypted model serving](https://github.com/pytorch/serve/blob/v0.5.0/docs/management_api.md#encrypted-model-serving) (not tested). Update streamlit to v1+
63+
5964
# FAQs
6065
- **Does torchserver keep running in the background?**
6166

@@ -65,7 +70,7 @@ If the server doesn't start for some reason check if your ports are already in u
6570

6671
These environment variables are passed to the torchserve command:
6772

68-
`ENVIRON_WHITELIST=["LD_LIBRARY_PATH","LC_CTYPE","LC_ALL","PATH","JAVA_HOME","PYTHONPATH","TS_CONFIG_FILE","LOG_LOCATION","METRICS_LOCATION"]`
73+
`ENVIRON_WHITELIST=["LD_LIBRARY_PATH","LC_CTYPE","LC_ALL","PATH","JAVA_HOME","PYTHONPATH","TS_CONFIG_FILE","LOG_LOCATION","METRICS_LOCATION","AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_DEFAULT_REGION"]`
6974

7075
- **How to change the logging format of torchserve?**
7176

requirements/install.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,2 @@
1-
streamlit==0.82.0
2-
click<8.0,>=7.0
3-
httpx>=0.16.0
1+
httpx >= 0.16.0
2+
streamlit == 1.2.0

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ def _prepare_extras():
7070
install_requires=setup_tools.load_requirements(
7171
file_name='install.txt'), # Optional
7272
extras_require=_prepare_extras(),
73-
python_requires='>=3.6',
73+
python_requires='>=3.7',
7474

7575
# test_suite='setup.get_test_suite',
7676
# tests_require=["coverage"],

torchserve_dashboard/api.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99

1010
ENVIRON_WHITELIST = [
1111
"LD_LIBRARY_PATH", "LC_CTYPE", "LC_ALL", "PATH", "JAVA_HOME", "PYTHONPATH",
12-
"TS_CONFIG_FILE", "LOG_LOCATION", "METRICS_LOCATION"
12+
"TS_CONFIG_FILE", "LOG_LOCATION", "METRICS_LOCATION",
13+
"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_DEFAULT_REGION"
1314
]
1415

1516
log = logging.getLogger(__name__)
@@ -18,14 +19,17 @@
1819
class LocalTS:
1920
def __init__(self,
2021
model_store: str,
21-
config_path: str,
22+
config_path: Optional[str] = None,
2223
log_location: Optional[str] = None,
23-
metrics_location: Optional[str] = None) -> None:
24+
metrics_location: Optional[str] = None,
25+
log_config: Optional[str] = None) -> None:
2426
new_env = {}
2527
env = os.environ
2628
for x in ENVIRON_WHITELIST:
2729
if x in env:
2830
new_env[x] = env[x]
31+
if config_path:
32+
new_env["TS_CONFIG_FILE"] = config_path
2933
if log_location:
3034
new_env["LOG_LOCATION"] = log_location
3135
if not os.path.isdir(log_location):
@@ -39,6 +43,7 @@ def __init__(self,
3943
self.config_path = config_path
4044
self.log_location = log_location
4145
self.metrics_location = metrics_location
46+
self.log_config = log_config
4247
self.env = new_env
4348

4449
def check_version(self) -> Tuple[str, Union[str, Exception]]:
@@ -62,6 +67,8 @@ def start_torchserve(self) -> str:
6267
self.log_location, "torchserve_dashboard.log"
6368
) if self.log_location is not None else None
6469
torchserve_cmd = f"torchserve --start --ncs --model-store {self.model_store} --ts-config {self.config_path}"
70+
if self.log_config:
71+
torchserve_cmd += f" --log-config {self.log_config}"
6572
p = subprocess.Popen(
6673
torchserve_cmd.split(" "),
6774
env=self.env,
@@ -132,6 +139,7 @@ def register_model(
132139
max_batch_delay: Optional[int] = None,
133140
initial_workers: Optional[int] = None,
134141
response_timeout: Optional[int] = None,
142+
is_encrypted: Optional[bool] = None,
135143
) -> Dict[str, str]:
136144

137145
req_url = self.address + "/models?url=" + mar_path + "&synchronous=false"
@@ -149,6 +157,8 @@ def register_model(
149157
req_url += "&initial_workers=" + str(initial_workers)
150158
if response_timeout:
151159
req_url += "&response_timeout=" + str(response_timeout)
160+
if is_encrypted:
161+
req_url += "&s3_sse_kms=true"
152162

153163
res = self.client.post(req_url)
154164
return res.json()

torchserve_dashboard/dash.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,24 @@
3434
default="./logs/metrics/",
3535
help="Passed as environment variable METRICS_LOCATION to Torchserve",
3636
)
37+
parser.add_argument(
38+
"--log_config",
39+
default=None,
40+
help="Overrides the default log4j.properties",
41+
)
3742
try:
3843
args = parser.parse_args()
3944
except SystemExit as e:
4045
os._exit(e.code)
4146

42-
47+
# Clean this up later
4348
def check_args(args):
4449
M_API = "http://127.0.0.1:8081"
4550
model_store = args.model_store
4651
config_path = args.config_path
4752
log_location = args.log_location
4853
metrics_location = args.metrics_location
54+
log_config = args.log_config
4955
if not os.path.exists(config_path):
5056
st.write(f"Can't find config file at {config_path}. Using default config instead")
5157
config_path = os.path.join(os.path.dirname(__file__), "default.torchserve.properties")
@@ -57,6 +63,8 @@ def check_args(args):
5763
model_store = c.split("=")[-1].strip()
5864
if c.startswith("management_address"):
5965
M_API = c.split("=")[-1].strip()
66+
else:
67+
st.write("Config file can't be found!")
6068

6169
if log_location:
6270
log_location = str(Path(log_location).resolve())
@@ -73,12 +81,12 @@ def check_args(args):
7381
st.write(f"Created model store directory {model_store}")
7482
os.makedirs(model_store, exist_ok=True)
7583

76-
return M_API, config, model_store, config_path, log_location, metrics_location
84+
return M_API, config, model_store, config_path, log_location, metrics_location, log_config
7785

7886

7987
st.title("Torchserve Management Dashboard")
8088
default_key = "None"
81-
api_address, config, model_store, config_path, log_location, metrics_location = check_args(args)
89+
api_address, config, model_store, config_path, log_location, metrics_location, log_config = check_args(args)
8290

8391

8492
def rerun():
@@ -101,7 +109,7 @@ def get_model_store():
101109

102110

103111
api = ManagementAPI(api_address, error_callback)
104-
ts = LocalTS(model_store, config_path, log_location, metrics_location)
112+
ts = LocalTS(model_store, config_path, log_location, metrics_location, log_config)
105113
ts_version,ts_error=ts.check_version() # doing it this way rather than ts.__version__ on purpose
106114
if ts_error:
107115
st.error(ts_error)
@@ -114,7 +122,7 @@ def get_model_store():
114122
# As a design choice I'm leaving config_path,log_location,metrics_location non-editable from the UI as a semi-security measure (maybe?:/)
115123
##########Sidebar##########
116124
st.sidebar.markdown("## Help")
117-
with st.sidebar.beta_expander(label="Show Paths:", expanded=False):
125+
with st.sidebar.expander(label="Show Paths:", expanded=False):
118126
st.markdown(f"### Model Store Path: \n {model_store}")
119127
st.markdown(f"### Config Path: \n {config_path}")
120128
st.markdown(f"### Log Location: \n {log_location}")
@@ -145,13 +153,13 @@ def get_model_store():
145153

146154
st.markdown(f"**Last Message**: {last_res()[0]}")
147155

148-
with st.beta_expander(label="Show torchserve config", expanded=False):
156+
with st.expander(label="Show torchserve config", expanded=False):
149157
st.write(config)
150158
st.markdown("[configuration docs](https://pytorch.org/serve/configuration.html)")
151159

152160
if torchserve_status:
153161

154-
with st.beta_expander(label="Register a model", expanded=False):
162+
with st.expander(label="Register a model", expanded=False):
155163

156164
st.markdown(
157165
"# Register a model [(docs)](https://pytorch.org/serve/management_api.html#register-a-model)"
@@ -160,12 +168,12 @@ def get_model_store():
160168
mar_path = placeholder.selectbox(
161169
"Choose mar file *", [default_key] + stored_models, index=0
162170
)
163-
# mar_path = os.path.join(model_store,mar_path)
164-
p = st.checkbox("manually enter path")
171+
p = st.checkbox("manually enter location")
165172
if p:
166173
mar_path = placeholder.text_input("Input mar file path*")
174+
167175
model_name = st.text_input(label="Model name (overrides predefined)")
168-
col1, col2 = st.beta_columns(2)
176+
col1, col2 = st.columns(2)
169177
batch_size = col1.number_input(label="batch_size", value=0, min_value=0, step=1)
170178
max_batch_delay = col2.number_input(
171179
label="max_batch_delay", value=0, min_value=0, step=100
@@ -178,7 +186,7 @@ def get_model_store():
178186
)
179187
handler = col1.text_input(label="handler")
180188
runtime = col2.text_input(label="runtime")
181-
189+
is_encrypted = st.checkbox("SSE-KMS Encrypted", help="Refer to https://github.com/pytorch/serve/blob/v0.5.0/docs/management_api.md#encrypted-model-serving")
182190
proceed = st.button("Register")
183191
if proceed:
184192
if mar_path != default_key:
@@ -192,13 +200,14 @@ def get_model_store():
192200
max_batch_delay=max_batch_delay,
193201
initial_workers=initial_workers,
194202
response_timeout=response_timeout,
203+
is_encrypted=is_encrypted,
195204
)
196205
last_res()[0] = res
197206
rerun()
198207
else:
199208
st.warning(":octagonal_sign: Fill the required fileds!")
200209

201-
with st.beta_expander(label="Remove a model", expanded=False):
210+
with st.expander(label="Remove a model", expanded=False):
202211

203212
st.header("Remove a model")
204213
model_name = st.selectbox(
@@ -221,7 +230,7 @@ def get_model_store():
221230
else:
222231
st.warning(":octagonal_sign: Pick a model & version!")
223232

224-
with st.beta_expander(label="Get model details", expanded=False):
233+
with st.expander(label="Get model details", expanded=False):
225234

226235
st.header("Get model details")
227236
model_name = st.selectbox(
@@ -243,7 +252,7 @@ def get_model_store():
243252
res = api.get_model(model_name, version)
244253
st.write(res)
245254

246-
with st.beta_expander(label="Scale workers", expanded=False):
255+
with st.expander(label="Scale workers", expanded=False):
247256
st.markdown(
248257
"# Scale workers [(docs)](https://pytorch.org/serve/management_api.html#scale-workers)"
249258
)
@@ -257,7 +266,7 @@ def get_model_store():
257266
versions = [m["modelVersion"] for m in versions]
258267
version = st.selectbox("Choose version", ["All"] + versions, index=0)
259268

260-
col1, col2, col3 = st.beta_columns(3)
269+
col1, col2, col3 = st.columns(3)
261270
min_worker = col1.number_input(
262271
label="min_worker(optional)", value=-1, min_value=-1, step=1
263272
)
@@ -286,7 +295,7 @@ def get_model_store():
286295
last_res()[0] = res
287296
rerun()
288297
if support_workflow:
289-
with st.beta_expander(label="Register Workflow", expanded=False):
298+
with st.expander(label="Register Workflow", expanded=False):
290299
st.markdown(
291300
"# Register a workflow [(docs)](https://pytorch.org/serve/workflow_management_api.html#register-a-workflow)"
292301
)
@@ -296,7 +305,7 @@ def get_model_store():
296305
res = api.register_workflow(url, workflow_name)
297306
st.write(res)
298307

299-
with st.beta_expander(label="Show Workflow Details", expanded=False):
308+
with st.expander(label="Show Workflow Details", expanded=False):
300309
st.markdown(
301310
"# Describe a workflow [(docs)](https://pytorch.org/serve/workflow_management_api.html#describe-workflow)"
302311
)
@@ -310,7 +319,7 @@ def get_model_store():
310319
res = api.get_workflow(workflow_name)
311320
st.write(res)
312321

313-
with st.beta_expander(label="Unregister Workflow", expanded=False):
322+
with st.expander(label="Unregister Workflow", expanded=False):
314323
st.markdown(
315324
"# Unregister a Workflow [(docs)](https://pytorch.org/serve/workflow_management_api.html#unregister-a-workflow)"
316325
)
@@ -324,7 +333,7 @@ def get_model_store():
324333
res = api.unregister_workflow(workflow_name)
325334
st.write(res)
326335

327-
with st.beta_expander(label="List Workflows", expanded=False):
336+
with st.expander(label="List Workflows", expanded=False):
328337
st.markdown(
329338
"# List Workflows"
330339
)

tox.ini

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[tox]
2-
envlist=py36, pypy, flake8
2+
envlist=py37, pypy, flake8
33

44
[testenv]
55
commands=py.test --cov torchserve_dashboard {posargs}
@@ -8,7 +8,7 @@ deps=
88
pytest-cov
99

1010
[testenv:flake8]
11-
basepython = python3.6
11+
basepython = python3.7
1212
deps =
1313
flake8
1414
commands =

0 commit comments

Comments
 (0)