From d53cfa8dd719817cbfea48ad032c8181515df2a3 Mon Sep 17 00:00:00 2001 From: Manoop Talasila Date: Tue, 15 Oct 2019 12:22:42 -0400 Subject: [PATCH] Add Acumos xApp Adapter Issue-Id: RICAPP-4 Signed-off-by: Manoop Talasila Change-Id: I369577ccc1c392af769089712c4a882f876c4489 --- .gitignore | 2 + .gitreview | 4 + AcumosXappAdapter/config.json | 14 ++++ AcumosXappAdapter/iris_sklearn.py | 56 +++++++++++++ AcumosXappAdapter/rmracumosadapter.py | 127 ++++++++++++++++++++++++++++ AcumosXappAdapter/testdata.csv | 151 ++++++++++++++++++++++++++++++++++ 6 files changed, 354 insertions(+) create mode 100644 .gitignore create mode 100644 .gitreview create mode 100644 AcumosXappAdapter/config.json create mode 100644 AcumosXappAdapter/iris_sklearn.py create mode 100644 AcumosXappAdapter/rmracumosadapter.py create mode 100644 AcumosXappAdapter/testdata.csv diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..21276bf --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# OSx cruft +**/.DS_Store diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..07d953f --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=gerrit.o-ran-sc.org +port=29418 +project=ric-app/ml.git diff --git a/AcumosXappAdapter/config.json b/AcumosXappAdapter/config.json new file mode 100644 index 0000000..e425e82 --- /dev/null +++ b/AcumosXappAdapter/config.json @@ -0,0 +1,14 @@ +{ + "version": "0.1.1", + "microserviceRootURL": "http://acumos:3330/", + "methodRoot": "model/methods/", + "artifactRoot": "model/artifacts/", + "methods": { + "1": { + "service": "classify", + "content-type": "application/json", + "return-type": "application/json", + "return-rte": "2" + } + } +} diff --git a/AcumosXappAdapter/iris_sklearn.py b/AcumosXappAdapter/iris_sklearn.py new file mode 100644 index 0000000..7fd70fb --- /dev/null +++ b/AcumosXappAdapter/iris_sklearn.py @@ -0,0 +1,56 @@ +# ===============LICENSE_START======================================================= +# Acumos Apache-2.0 +# =================================================================================== +# Copyright (C) 2017-2018 AT&T Intellectual Property & Tech Mahindra. All rights reserved. +# =================================================================================== +# This Acumos software file is distributed by AT&T and Tech Mahindra +# under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# This file is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ===============LICENSE_END========================================================= + +from acumos.session import AcumosSession +from acumos.modeling import Model, List, create_dataframe + +import numpy as np +import pandas as pd +from sklearn.datasets import load_iris +from sklearn.ensemble import RandomForestClassifier + +iris = load_iris() +X = iris.data +y = iris.target + +clf = RandomForestClassifier(random_state=0) +clf.fit(X, y) + +# here, an appropriate NamedTuple type is inferred from a pandas DataFrame +X_df = pd.DataFrame(X, columns=['sepal_length', 'sepal_width', 'petal_length', 'petal_width']) +IrisDataFrame = create_dataframe('IrisDataFrame', X_df) + +# ================================================================================== +# # or equivalently: +# +# IrisDataFrame = create_namedtuple('IrisDataFrame', [('sepal_length', List[float]), +# ('sepal_width', List[float]), +# ('petal_length', List[float]), +# ('petal_width', List[float])]) +# ================================================================================== + +def classify_iris(df: IrisDataFrame) -> List[int]: + '''Returns an array of iris classifications''' + X = np.column_stack(df) + return clf.predict(X) + +model = Model(classify=classify_iris) + +session = AcumosSession() + +session.dump(model,'iris_sklearn','/Users/guy/Desktop') diff --git a/AcumosXappAdapter/rmracumosadapter.py b/AcumosXappAdapter/rmracumosadapter.py new file mode 100644 index 0000000..16ce726 --- /dev/null +++ b/AcumosXappAdapter/rmracumosadapter.py @@ -0,0 +1,127 @@ +# ========================LICENSE_START================================= +# O-RAN-SC +# %% +# Copyright (c) 2019 AT&T Intellectual Property. +# %% +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ========================LICENSE_END=================================== + +# Adapter from RMR to standard Acumos model microservices. Must be deployed in the same pod as the Acumos model. +# Translates RMR protocol messages into calls into Acumos RPC calls. + + +from rmr import rmr +import time +import sys +import signal +import json +import requests + +verbose = True +requireartifacts = True + +confdir = '/conf/' +conffilename = 'config.json' +protobuffilename = 'model.proto' +metadatafilename = 'metadata.json' + +configfilename = confdir + conffilename + +if verbose: + print("Reading config file") + +# Fetch and parse config file which must be mounted as a volume during deployment +try: + with open(configfilename) as f: + conf = json.load(f) +except: + print('Cannot read/parse config file at', configfilename, '; aborting') + exit(1) + +methodurl = conf['microserviceRootURL'] + conf['methodRoot'] +artifacturl = conf["microserviceRootURL"] + conf['artifactRoot'] + +if verbose: + print ('\nRetrieving artifacts from Acumos model microservice\n') + +# See if we can retrieve protobuf and metadata artifacts from running model. Not all models may provide these, but we +# should have a retry mechanism added for robustness +try: + r = requests.get(artifacturl + 'protobuf') + protobuf = r.content + with open(confdir + protobuffilename, 'wb') as f: + f.write(protobuf) + if verbose: + print('Protbuf:') + print(protobuf.decode('ascii')) + r = requests.get(artifacturl + 'metadata') + metadata = r.content + with open(confdir + metadatafilename, 'wb') as f: + f.write(metadata) + if verbose: + print('\nMetadata:') + print(metadata.decode('ascii')) +except: + if requireartifacts: + print('Problem with retrieving/saving model protobuf and/or metadata; aborting.') + +method1 = conf['methods']['1'] +method1url = methodurl + method1['service'] +method1headers = {'content-type': method1['content-type'], 'accept': method1['return-type']} + +if verbose: + print('\nInitializing RMR\n') + +if verbose: + print('\Awaiting connections') + + +# NNG cleanup on signal +def signal_handler(sig, frame): + if verbose: + print('SIGINT received! Cleaning up rmr') + rmr.rmr_close(mrc) + print("Exiting") + sys.exit(0) + + +# Initialize RMR +mrc = rmr.rmr_init("4560".encode('utf-8'), rmr.RMR_MAX_RCV_BYTES, 0x00) +while rmr.rmr_ready(mrc) == 0: + time.sleep(1) + if verbose: + print("Not yet ready") +rmr.rmr_set_stimeout(mrc, 2) + + +# Capture ctrl-c +signal.signal(signal.SIGINT, signal_handler) + + +sbuf = None +while True: + if verbose: + print("Waiting for a message; will time out after 2000ms") + sbuf = rmr.rmr_torcv_msg(mrc, sbuf, 2000) + summary = rmr.message_summary(sbuf) + if verbose and summary['message state'] == 12: + print("Nothing received.") + else: + if verbose: + print("Message received: {}".format(summary)) + payload = sbuf['payload'] + # Call Acumos microservice + r = requests.post(method1url, headers=method1headers, body=payload) + val = r.content + rmr.set_payload_and_length(val, sbuf) + sbuf = rmr.rmr_rts_msg(mrc, sbuf) diff --git a/AcumosXappAdapter/testdata.csv b/AcumosXappAdapter/testdata.csv new file mode 100644 index 0000000..fd0a1e6 --- /dev/null +++ b/AcumosXappAdapter/testdata.csv @@ -0,0 +1,151 @@ +5.1,3.5,1.4,0.2 +4.9,3.0,1.4,0.2 +4.7,3.2,1.3,0.2 +4.6,3.1,1.5,0.2 +5.0,3.6,1.4,0.2 +5.4,3.9,1.7,0.4 +4.6,3.4,1.4,0.3 +5.0,3.4,1.5,0.2 +4.4,2.9,1.4,0.2 +4.9,3.1,1.5,0.1 +5.4,3.7,1.5,0.2 +4.8,3.4,1.6,0.2 +4.8,3.0,1.4,0.1 +4.3,3.0,1.1,0.1 +5.8,4.0,1.2,0.2 +5.7,4.4,1.5,0.4 +5.4,3.9,1.3,0.4 +5.1,3.5,1.4,0.3 +5.7,3.8,1.7,0.3 +5.1,3.8,1.5,0.3 +5.4,3.4,1.7,0.2 +5.1,3.7,1.5,0.4 +4.6,3.6,1.0,0.2 +5.1,3.3,1.7,0.5 +4.8,3.4,1.9,0.2 +5.0,3.0,1.6,0.2 +5.0,3.4,1.6,0.4 +5.2,3.5,1.5,0.2 +5.2,3.4,1.4,0.2 +4.7,3.2,1.6,0.2 +4.8,3.1,1.6,0.2 +5.4,3.4,1.5,0.4 +5.2,4.1,1.5,0.1 +5.5,4.2,1.4,0.2 +4.9,3.1,1.5,0.2 +5.0,3.2,1.2,0.2 +5.5,3.5,1.3,0.2 +4.9,3.6,1.4,0.1 +4.4,3.0,1.3,0.2 +5.1,3.4,1.5,0.2 +5.0,3.5,1.3,0.3 +4.5,2.3,1.3,0.3 +4.4,3.2,1.3,0.2 +5.0,3.5,1.6,0.6 +5.1,3.8,1.9,0.4 +4.8,3.0,1.4,0.3 +5.1,3.8,1.6,0.2 +4.6,3.2,1.4,0.2 +5.3,3.7,1.5,0.2 +5.0,3.3,1.4,0.2 +7.0,3.2,4.7,1.4 +6.4,3.2,4.5,1.5 +6.9,3.1,4.9,1.5 +5.5,2.3,4.0,1.3 +6.5,2.8,4.6,1.5 +5.7,2.8,4.5,1.3 +6.3,3.3,4.7,1.6 +4.9,2.4,3.3,1.0 +6.6,2.9,4.6,1.3 +5.2,2.7,3.9,1.4 +5.0,2.0,3.5,1.0 +5.9,3.0,4.2,1.5 +6.0,2.2,4.0,1.0 +6.1,2.9,4.7,1.4 +5.6,2.9,3.6,1.3 +6.7,3.1,4.4,1.4 +5.6,3.0,4.5,1.5 +5.8,2.7,4.1,1.0 +6.2,2.2,4.5,1.5 +5.6,2.5,3.9,1.1 +5.9,3.2,4.8,1.8 +6.1,2.8,4.0,1.3 +6.3,2.5,4.9,1.5 +6.1,2.8,4.7,1.2 +6.4,2.9,4.3,1.3 +6.6,3.0,4.4,1.4 +6.8,2.8,4.8,1.4 +6.7,3.0,5.0,1.7 +6.0,2.9,4.5,1.5 +5.7,2.6,3.5,1.0 +5.5,2.4,3.8,1.1 +5.5,2.4,3.7,1.0 +5.8,2.7,3.9,1.2 +6.0,2.7,5.1,1.6 +5.4,3.0,4.5,1.5 +6.0,3.4,4.5,1.6 +6.7,3.1,4.7,1.5 +6.3,2.3,4.4,1.3 +5.6,3.0,4.1,1.3 +5.5,2.5,4.0,1.3 +5.5,2.6,4.4,1.2 +6.1,3.0,4.6,1.4 +5.8,2.6,4.0,1.2 +5.0,2.3,3.3,1.0 +5.6,2.7,4.2,1.3 +5.7,3.0,4.2,1.2 +5.7,2.9,4.2,1.3 +6.2,2.9,4.3,1.3 +5.1,2.5,3.0,1.1 +5.7,2.8,4.1,1.3 +6.3,3.3,6.0,2.5 +5.8,2.7,5.1,1.9 +7.1,3.0,5.9,2.1 +6.3,2.9,5.6,1.8 +6.5,3.0,5.8,2.2 +7.6,3.0,6.6,2.1 +4.9,2.5,4.5,1.7 +7.3,2.9,6.3,1.8 +6.7,2.5,5.8,1.8 +7.2,3.6,6.1,2.5 +6.5,3.2,5.1,2.0 +6.4,2.7,5.3,1.9 +6.8,3.0,5.5,2.1 +5.7,2.5,5.0,2.0 +5.8,2.8,5.1,2.4 +6.4,3.2,5.3,2.3 +6.5,3.0,5.5,1.8 +7.7,3.8,6.7,2.2 +7.7,2.6,6.9,2.3 +6.0,2.2,5.0,1.5 +6.9,3.2,5.7,2.3 +5.6,2.8,4.9,2.0 +7.7,2.8,6.7,2.0 +6.3,2.7,4.9,1.8 +6.7,3.3,5.7,2.1 +7.2,3.2,6.0,1.8 +6.2,2.8,4.8,1.8 +6.1,3.0,4.9,1.8 +6.4,2.8,5.6,2.1 +7.2,3.0,5.8,1.6 +7.4,2.8,6.1,1.9 +7.9,3.8,6.4,2.0 +6.4,2.8,5.6,2.2 +6.3,2.8,5.1,1.5 +6.1,2.6,5.6,1.4 +7.7,3.0,6.1,2.3 +6.3,3.4,5.6,2.4 +6.4,3.1,5.5,1.8 +6.0,3.0,4.8,1.8 +6.9,3.1,5.4,2.1 +6.7,3.1,5.6,2.4 +6.9,3.1,5.1,2.3 +5.8,2.7,5.1,1.9 +6.8,3.2,5.9,2.3 +6.7,3.3,5.7,2.5 +6.7,3.0,5.2,2.3 +6.3,2.5,5.0,1.9 +6.5,3.0,5.2,2.0 +6.2,3.4,5.4,2.3 +5.9,3.0,5.1,1.8 + -- 2.16.6