Skip to content

Commit a32c233

Browse files
Merge pull request #19 from mlcommons/dev
Major update to support CM v2.2.0
2 parents 8fa290e + b838091 commit a32c233

File tree

42 files changed

+626
-71
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+626
-71
lines changed

README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
# Cross-platform CM interface for DevOps, MLOps, AIOps and MLPerf
1+
## Unified and cross-platform CM interface for DevOps, MLOps and MLPerf
22

33
[![License](https://img.shields.io/badge/License-Apache%202.0-green)](LICENSE.md)
4+
[![Python Version](https://img.shields.io/badge/python-3+-blue.svg)](https://github.com/mlcommons/ck/tree/master/cm/cmind)
45
[![Powered by CM](https://img.shields.io/badge/Powered_by-MLCommons%20CM-blue)](https://github.com/mlcommons/ck).
6+
[![Downloads](https://static.pepy.tech/badge/cmind)](https://pepy.tech/project/cmind)
57

68
This repository contains reusable and cross-platform automation recipes to run DevOps, MLOps, AIOps and MLPerf
79
via a simple and human-readable [Collective Mind interface (CM)](https://github.com/mlcommons/ck)
@@ -16,14 +18,23 @@ These automation recipes are being developed and maintained
1618
by the [MLCommons Task Force on Automation and Reproducibility](https://github.com/mlcommons/ck/blob/master/docs/taskforce.md)
1719
with [great contributions](CONTRIBUTING.md) from the community.
1820

19-
### Catalog
21+
## Tests
22+
23+
[![CM script automation test](https://github.com/mlcommons/cm4mlops/actions/workflows/test-cm-scripts.yml/badge.svg)](https://github.com/mlcommons/cm4mlops/actions/workflows/test-cm-scripts.yml)
24+
[![CM script automation features test](https://github.com/mlcommons/cm4mlops/actions/workflows/test-cm-script-features.yml/badge.svg)](https://github.com/mlcommons/cm4mlops/actions/workflows/test-cm-script-features.yml)
25+
[![MLPerf loadgen with HuggingFace bert onnx fp32 squad model](https://github.com/mlcommons/cm4mlops/actions/workflows/test-mlperf-loadgen-onnx-huggingface-bert-fp32-squad.yml/badge.svg)](https://github.com/mlcommons/cm4mlops/actions/workflows/test-mlperf-loadgen-onnx-huggingface-bert-fp32-squad.yml)
26+
[![MLPerf inference MLCommons C++ ResNet50](https://github.com/mlcommons/cm4mlops/actions/workflows/test-mlperf-inference-mlcommons-cpp-resnet50.yml/badge.svg)](https://github.com/mlcommons/cm4mlops/actions/workflows/test-mlperf-inference-mlcommons-cpp-resnet50.yml)
27+
[![image classification with ONNX](https://github.com/mlcommons/cm4mlops/actions/workflows/test-image-classification-onnx.yml/badge.svg)](https://github.com/mlcommons/cm4mlops/actions/workflows/test-image-classification-onnx.yml)
28+
29+
30+
## Catalog
2031

2132
See the automatically generated catalog [online](https://access.cknowledge.org/playground/?action=scripts).
2233

23-
### License
34+
## License
2435

2536
[Apache 2.0](LICENSE.md)
2637

27-
### Copyright
38+
## Copyright
2839

2940
2022-2024 [MLCommons](https://mlcommons.org)

automation/script/_cm.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
"alias": "script",
33
"automation_alias": "automation",
44
"automation_uid": "bbeb15d8f0a944a4",
5+
"min_cm_version": "2.2.0",
56
"deps": {
67
"cache": "cache,541d6f712a6b464e"
78
},
89
"desc": "Making native scripts more portable, interoperable and deterministic",
9-
"developers": "[Arjun Suresh](https://www.linkedin.com/in/arjunsuresh), [Grigori Fursin](https://cKnowledge.org/gfursin)",
10+
"developers": "Arjun Suresh and Grigori Fursin",
1011
"actions_with_help":["run", "docker"],
1112
"sort": 1000,
1213
"tags": [

automation/script/module.py

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
from cmind.automation import Automation
1616
from cmind import utils
17+
from cmind import __version__ as current_cm_version
1718

1819
class CAutomation(Automation):
1920
"""
@@ -150,6 +151,8 @@ def run(self, i):
150151
inside a script specified by these tags
151152
152153
(debug_script) (bool): if True, debug current script (set debug_script_tags to the tags of a current script)
154+
(debug_uid) (str): if True, set CM_TMP_DEBUG_UID to this number to enable
155+
remote python debugging of scripts and wrapped apps/tools
153156
(detected_versions) (dict): All the used scripts and their detected_versions
154157
155158
(verbose) (bool): if True, prints all tech. info about script execution (False by default)
@@ -180,6 +183,9 @@ def run(self, i):
180183
(skip_sudo) (bool): if True, set env['CM_TMP_SKIP_SUDO']='yes'
181184
to let scripts deal with that
182185
186+
(silent) (bool): if True, attempt to suppress all info if supported
187+
(sets CM_TMP_SILENT=yes)
188+
(s) (bool): the same as 'silent'
183189
...
184190
185191
Returns:
@@ -309,14 +315,6 @@ def _run(self, i):
309315

310316
print_env = i.get('print_env', False)
311317

312-
verbose = False
313-
314-
if 'verbose' in i: verbose=i['verbose']
315-
elif 'v' in i: verbose=i['v']
316-
317-
if verbose:
318-
env['CM_VERBOSE']='yes'
319-
320318
show_time = i.get('time', False)
321319
show_space = i.get('space', False)
322320

@@ -331,6 +329,10 @@ def _run(self, i):
331329
fake_run = i.get('fake_run', False)
332330
fake_run = i.get('fake_run', False) if 'fake_run' in i else i.get('prepare', False)
333331
if fake_run: env['CM_TMP_FAKE_RUN']='yes'
332+
333+
debug_uid = i.get('debug_uid', '')
334+
if debug_uid!='':
335+
env['CM_TMP_DEBUG_UID'] = debug_uid
334336

335337
fake_deps = i.get('fake_deps', False)
336338
if fake_deps: env['CM_TMP_FAKE_DEPS']='yes'
@@ -348,6 +350,28 @@ def _run(self, i):
348350
if fake_deps:
349351
run_state['fake_deps'] = True
350352

353+
# Check verbose and silent
354+
verbose = False
355+
356+
silent = True if str(i.get('silent', '')).lower() in ['true', 'yes', 'on'] else False
357+
358+
if not silent:
359+
silent = True if str(i.get('s', '')).lower() in ['true', 'yes', 'on'] else False
360+
361+
if silent:
362+
if 'verbose' in i: del(i['verbose'])
363+
if 'v' in i: del(i['v'])
364+
env['CM_TMP_SILENT']='yes'
365+
run_state['tmp_silent']=True
366+
367+
if 'verbose' in i: verbose=i['verbose']
368+
elif 'v' in i: verbose=i['v']
369+
370+
if verbose:
371+
env['CM_VERBOSE']='yes'
372+
run_state['tmp_verbose']=True
373+
374+
351375
print_deps = i.get('print_deps', False)
352376
print_readme = i.get('print_readme', False)
353377

@@ -517,8 +541,9 @@ def _run(self, i):
517541
# if verbose:
518542
# print ('')
519543

520-
print ('')
521-
print (recursion_spaces + '* ' + cm_script_info)
544+
if not run_state.get('tmp_silent', False):
545+
print ('')
546+
print (recursion_spaces + '* ' + cm_script_info)
522547

523548

524549
#############################################################################
@@ -703,6 +728,15 @@ def _run(self, i):
703728
meta = script_artifact.meta
704729
path = script_artifact.path
705730

731+
# Check min CM version requirement
732+
min_cm_version = meta.get('min_cm_version','').strip()
733+
if min_cm_version != '':
734+
# Check compare version while avoiding craches for older version
735+
if 'compare_versions' in dir(utils):
736+
comparison = utils.compare_versions(current_cm_version, min_cm_version)
737+
if comparison < 0:
738+
return {'return':1, 'error':'CM script requires CM version >= {} while current CM version is {} - please update using "pip install cmind -U"'.format(min_cm_version, current_cm_version)}
739+
706740
# Check path to repo
707741
script_repo_path = script_artifact.repo_path
708742

@@ -1081,7 +1115,8 @@ def _run(self, i):
10811115
if r['return']>0: return r
10821116
version = r['meta'].get('version')
10831117

1084-
print (recursion_spaces + ' ! load {}'.format(path_to_cached_state_file))
1118+
if not run_state.get('tmp_silent', False):
1119+
print (recursion_spaces + ' ! load {}'.format(path_to_cached_state_file))
10851120

10861121

10871122
################################################################################################
@@ -1763,19 +1798,20 @@ def _run(self, i):
17631798
input ('Press Enter to continue ...')
17641799

17651800
# Check if need to print some final info such as path to model, etc
1766-
print_env_at_the_end = meta.get('print_env_at_the_end',{})
1767-
if len(print_env_at_the_end)>0:
1768-
print ('')
1801+
if not run_state.get('tmp_silent', False):
1802+
print_env_at_the_end = meta.get('print_env_at_the_end',{})
1803+
if len(print_env_at_the_end)>0:
1804+
print ('')
17691805

1770-
for p in sorted(print_env_at_the_end):
1771-
t = print_env_at_the_end[p]
1772-
if t == '': t = 'ENV[{}]'.format(p)
1806+
for p in sorted(print_env_at_the_end):
1807+
t = print_env_at_the_end[p]
1808+
if t == '': t = 'ENV[{}]'.format(p)
17731809

1774-
v = new_env.get(p, None)
1810+
v = new_env.get(p, None)
17751811

1776-
print ('{}: {}'.format(t, str(v)))
1812+
print ('{}: {}'.format(t, str(v)))
17771813

1778-
print ('')
1814+
print ('')
17791815

17801816
return rr
17811817

@@ -2887,6 +2923,7 @@ def _run_deps(self, deps, clean_env_keys_deps, env, state, const, const_state, a
28872923

28882924
# Run collective script via CM API:
28892925
# Not very efficient but allows logging - can be optimized later
2926+
28902927
ii = {
28912928
'action':'run',
28922929
'automation':utils.assemble_cm_object(self.meta['alias'], self.meta['uid']),
@@ -2900,6 +2937,7 @@ def _run_deps(self, deps, clean_env_keys_deps, env, state, const, const_state, a
29002937
'add_deps_recursive':add_deps_recursive,
29012938
'debug_script_tags':debug_script_tags,
29022939
'verbose':verbose,
2940+
'silent':run_state.get('tmp_silent', False),
29032941
'time':show_time,
29042942
'run_state':run_state
29052943

@@ -4295,8 +4333,9 @@ def prepare_and_run_script_with_postprocessing(i, postprocess="postprocess"):
42954333
print (recursion_spaces + ' - Running native script "{}" from temporal script "{}" in "{}" ...'.format(path_to_run_script, run_script, cur_dir))
42964334
print ('')
42974335

4298-
print (recursion_spaces + ' ! cd {}'.format(cur_dir))
4299-
print (recursion_spaces + ' ! call {} from {}'.format(path_to_run_script, run_script))
4336+
if not run_state.get('tmp_silent', False):
4337+
print (recursion_spaces + ' ! cd {}'.format(cur_dir))
4338+
print (recursion_spaces + ' ! call {} from {}'.format(path_to_run_script, run_script))
43004339

43014340

43024341
# Prepare env variables
@@ -4388,7 +4427,8 @@ def prepare_and_run_script_with_postprocessing(i, postprocess="postprocess"):
43884427

43894428

43904429
if postprocess != '' and customize_code is not None and postprocess in dir(customize_code):
4391-
print (recursion_spaces+' ! call "{}" from {}'.format(postprocess, customize_code.__file__))
4430+
if not run_state.get('tmp_silent', False):
4431+
print (recursion_spaces+' ! call "{}" from {}'.format(postprocess, customize_code.__file__))
43924432

43934433
if len(posthook_deps)>0 and (postprocess == "postprocess"):
43944434
r = script_automation._call_run_deps(posthook_deps, local_env_keys, local_env_keys_from_meta, env, state, const, const_state,

automation/script/template/run.sh

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,11 @@
77

88
#${CM_PYTHON_BIN_WITH_PATH} contains the path to python binary if "get,python" is added as a dependency
99

10-
11-
12-
function exit_if_error() {
13-
test $? -eq 0 || exit $?
14-
}
15-
16-
function run() {
17-
echo "Running: "
18-
echo "$1"
19-
echo ""
20-
if [[ ${CM_FAKE_RUN} != 'yes' ]]; then
21-
eval "$1"
22-
exit_if_error
23-
fi
24-
}
25-
26-
#Add your run commands here...
27-
# run "$CM_RUN_CMD"
10+
echo "Running: "
11+
echo "${CM_RUN_CMD}"
12+
echo ""
13+
14+
if [[ ${CM_FAKE_RUN} != "yes" ]]; then
15+
eval "${CM_RUN_CMD}"
16+
test $? -eq 0 || exit 1
17+
fi

cmr.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ uid: 9e97bb72b0474657
33

44
git: true
55

6+
version: 2.2.0
7+
68
deps:
79
- alias: mlcommons@ck
810
uid: a4705959af8e447a

script/app-image-classification-onnx-py/customize.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ def preprocess(i):
77
os_info = i['os_info']
88
env = i['env']
99

10-
print ('')
11-
print ('Running preprocess function in customize.py ...')
10+
# print ('')
11+
# print ('Running preprocess function in customize.py ...')
1212

1313
return {'return':0}
1414

@@ -55,10 +55,11 @@ def postprocess(i):
5555

5656
top_classification = data.get('top_classification','')
5757

58-
if top_classification!='':
59-
print ('')
60-
x = 'Top classification: {}'.format(top_classification)
61-
print ('='*len(x))
62-
print (x)
58+
if env.get('CM_TMP_SILENT','')!='yes':
59+
if top_classification!='':
60+
print ('')
61+
x = 'Top classification: {}'.format(top_classification)
62+
print ('='*len(x))
63+
print (x)
6364

6465
return {'return':0}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
alias: create-custom-cache-entry
2+
uid: 485741440fbe4236
3+
4+
automation_alias: script
5+
automation_uid: 5b4e0237da074764
6+
7+
tags:
8+
- create
9+
- custom
10+
- cache
11+
- entry
12+
13+
category: CM automation
14+
15+
cache: true
16+
17+
input_mapping:
18+
env_key: CM_CUSTOM_CACHE_ENTRY_ENV_KEY
19+
env_key2: CM_CUSTOM_CACHE_ENTRY_ENV_KEY2
20+
path: CM_CUSTOM_CACHE_ENTRY_PATH
21+
to: CM_CUSTOM_CACHE_ENTRY_PATH
22+
23+
new_env_keys:
24+
- CM_CUSTOM_CACHE_ENTRY*
25+
26+
print_env_at_the_end:
27+
CM_CUSTOM_CACHE_ENTRY_PATH: "Path to custom cache entry"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from cmind import utils
2+
import os
3+
import shutil
4+
5+
def preprocess(i):
6+
7+
# CM script internal variables
8+
env = i['env']
9+
10+
extra_cache_tags = []
11+
if env.get('CM_EXTRA_CACHE_TAGS','').strip() == '':
12+
print ('')
13+
extra_cache_tags_str = input('Enter extra tags for the custom CACHE entry separated by comma: ')
14+
15+
extra_cache_tags = extra_cache_tags_str.strip().split(',')
16+
17+
return {'return':0, 'add_extra_cache_tags':extra_cache_tags}
18+
19+
def postprocess(i):
20+
21+
env = i['env']
22+
23+
path = env.get('CM_CUSTOM_CACHE_ENTRY_PATH','').strip()
24+
25+
if path!='':
26+
if not os.path.isdir(path):
27+
os.makedirs(path)
28+
else:
29+
path = os.getcwd()
30+
31+
x = ''
32+
env_key = env.get('CM_CUSTOM_CACHE_ENTRY_ENV_KEY', '')
33+
if env_key != '': x = env_key+'_'
34+
35+
env['CM_CUSTOM_CACHE_ENTRY_{}PATH'.format(x)] = path
36+
env['CM_CUSTOM_CACHE_ENTRY_PATH'] = path
37+
38+
env_key2 = env.get('CM_CUSTOM_CACHE_ENTRY_ENV_KEY2', '')
39+
v = env.get(env_key2, '')
40+
real_path = v if v != '' else path
41+
42+
env['CM_CUSTOM_CACHE_ENTRY_{}REAL_PATH'.format(x)] = real_path
43+
44+
return {'return': 0}

script/download-file/_cm.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
"input_description": {},
1717
"input_mapping": {
1818
"download_path": "CM_DOWNLOAD_PATH",
19+
"output_file": "CM_DOWNLOAD_FILENAME",
1920
"from": "CM_DOWNLOAD_LOCAL_FILE_PATH",
2021
"local_path": "CM_DOWNLOAD_LOCAL_FILE_PATH",
2122
"store": "CM_DOWNLOAD_PATH",
2223
"url": "CM_DOWNLOAD_URL",
2324
"verify": "CM_VERIFY_SSL",
25+
"verify_ssl": "CM_VERIFY_SSL",
2426
"md5sum": "CM_DOWNLOAD_CHECKSUM"
2527
},
2628
"new_env_keys": [

0 commit comments

Comments
 (0)