def build_app(pargs): '''Builds and returns a Flask app''' downstream = [] if path.exists('runtime.json'): with open('runtime.json') as f: runtime = json.load(f) # ad-hoc way of giving the app runtime parameters if not pargs.no_downstream: downstream = runtime['downstream'] # list of IP:port/path urls print("Found downstream forward routes {}".format(downstream)) else: pargs.return_output = True model = load_model(pargs.modeldir) # refers to ./model dir in pwd. generated by helper script also in this dir app = Flask(__name__) app.json_io = pargs.json_io # store io flag app.return_output = not pargs.no_output # store output # dynamically add handlers depending on model capabilities for method_name, method in model.methods.items(): handler = partial(invoke_method, model_method=method, downstream=downstream) url = "/{}".format(method_name) app.add_url_rule(url, method_name, handler, methods=['POST', 'GET']) # render down the input in few forms typeInput = list(method.pb_input_type.DESCRIPTOR.fields_by_name.keys()) # render down the output in few forms typeOutput = list(method.pb_output_type.DESCRIPTOR.fields_by_name.keys()) print("Adding route {} [input:{}, output:{}]".format(url, typeInput, typeOutput)) return app
def main(config={}): import argparse parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter, description='a wrapped model caller', epilog="Call to execute a single review sample or a textual sample \n" \ " (review) python util_call.py -m data/model -u \"http://localhost:8884\"\n" \ " (text) python util_call.py -t -m data/model3-setiment-ex_text-to-float -u \"http://acumos-gpu.research.att.com:8760\" -n sent_predict\n ") submain = parser.add_argument_group('main execution and evaluation functionality') submain.add_argument('-m', '--model_path', type=str, default='data/model2b-review-text', help="path to dumped model (for protobuf definitions)") submain.add_argument('-u', '--url_host', type=str, default=None, help="URL to target model (without function url, e.g. http://localhost:8884)") submain.add_argument('-n', '--function_name', type=str, default='classify', help="name of primary function to execute") submain.add_argument('-t', '--text_only-only', dest='text_only', action='store_true', default=False, help='run a text-only dataframe') submain.add_argument('-v', '--version_updated', dest='version_updated', action='store_true', default=False, help='run in an updated model version') config.update(vars(parser.parse_args())) # pargs, unparsed = parser.parse_known_args() # load model from disk, see that it is a nicely "wrapped" model wrapped_model = load_model(config['model_path']) print("----- Wrapped Model -------") print(wrapped_model) # create data frame if config['text_only']: X = [["I didn't like it much. It was such a rubbery item"], ["that was fantastic!"], ["perfect"]] else: X = [[[0,0], "I've had better", "not much", int(time.time()), ["office products"], "rubbery item"]] print("----- Dataframe -------") print(X) # score model with sample dataframe res_list, _ = score_model(wrapped_model, X, config['version_updated'], url_remote=config['url_host'], name_function=config['function_name']) #, ) print("----- Result -------") print(res_list)
def _init_runner(model_dir, timeout=_GETDATA_TIMEOUT_MS): '''Helper function which creates, configures, and returns model runner and DCAE objects''' dcae = Dcae() model = load_model(model_dir) runner = ModelRunner(model, dcae.env.getdata, dcae.env.senddata, dcae.config, timeout) dcae.health_checks.append(runner.health_check) dcae.on_configs.append(runner.on_config) return runner, dcae
def _mock_model(yield_model=True): '''Context manager that yields an acumos.wrapped.WrappedModel model for testing purposes''' def add(x: int, y: int) -> int: return x + y def multiply(x: int, y: int) -> int: return x * y model = Model(add=add, multiply=multiply) session = AcumosSession() with TemporaryDirectory() as tdir: session.dump(model, 'test-model', tdir) model_dir = os.path.join(tdir, 'test-model') wrapped_model = load_model(model_dir) yield wrapped_model if yield_model else model_dir
def _build_app(model_dir, cors): '''Builds and returns a Flask app''' connexion_app = App(__name__, specification_dir=model_dir) connexion_app.add_api('oas.yaml', resolver=_CustomResolver()) flask_app = connexion_app.app flask_app.model = load_model(model_dir) flask_app.model_dir = model_dir flask_app.methods_info = _read_methods(model_dir) @flask_app.route('/') def redirect_ui(): return redirect('/ui') _apply_cors(flask_app, cors) return flask_app
def test_raw_type(func, f_in, f_out, in_media_type, out_media_type, in_is_raw, out_is_raw): '''Tests to make sure that supported raw data type models are working correctly''' model = Model(transform=func) model_name = 'my-model' with TemporaryDirectory() as tdir: with _dump_model(model, model_name) as dump_dir: _copy_dir(dump_dir, tdir, model_name) copied_dump_dir = path_join(tdir, model_name) metadata_file_path = path_join(copied_dump_dir, 'metadata.json') with open(metadata_file_path) as metadata_file: metadata_json = json.load(metadata_file) assert metadata_json['methods']['transform']['input'][ 'media_type'] == in_media_type assert metadata_json['methods']['transform']['output'][ 'media_type'] == out_media_type wrapped_model = load_model(copied_dump_dir) if in_is_raw: wrapped_return = wrapped_model.transform.from_raw(f_in) else: arguments = model.transform.input_type(*f_in) arguments_pb_msg = _pack_pb_msg(arguments, wrapped_model.transform._module) wrapped_return = wrapped_model.transform.from_pb_msg( arguments_pb_msg) if out_is_raw: ret = wrapped_return.as_raw() else: ret_pb_msg = wrapped_return.as_pb_msg() ret = _unpack_pb_msg(model.transform.output_type, ret_pb_msg).value assert ret == f_out
from sklearn.datasets import load_iris from acumos.wrapped import load_model if __name__ == '__main__': '''Main''' parser = argparse.ArgumentParser() parser.add_argument("--uri", default='http://127.0.0.1:3330/transform') parser.add_argument("--sleep", default=5) parser.add_argument("--modeldir", type=str, default='model') parser.add_argument("--csvdata", type=str, default='') pargs = parser.parse_args() model = load_model( pargs.modeldir ) # refers to ./model dir in pwd. generated by helper script also in this dir if pargs.csvdata: import pandas as pd dfRaw = pd.read_csv(pargs.csvdata) X = dfRaw.as_matrix() else: iris = load_iris() X = iris.data # build protobuf message that model consumes DataFrame = model.transform.pb_input_type X_msg = DataFrame() for col, field in enumerate(DataFrame.DESCRIPTOR.fields):
def __init__(self, config, model_dir): '''Helper class that invokes the model runner's APIs''' self._config = config self._model = load_model(model_dir)
def _generic_test(func, in_, out, wrapped_eq=eq, pb_mg_eq=eq, pb_bytes_eq=eq, dict_eq=eq, json_eq=eq, preload=None, reqs=None, skip=None): '''Reusable wrap test routine with swappable equality functions''' model = Model(transform=func) model_name = 'my-model' with TemporaryDirectory() as tdir: with _dump_model(model, model_name, reqs) as dump_dir: _copy_dir(dump_dir, tdir, model_name) if preload is not None: preload() copied_dump_dir = path_join(tdir, model_name) wrapped_model = load_model(copied_dump_dir) TransIn = model.transform.input_type TransOut = model.transform.output_type trans_in = TransIn(*in_) trans_out = TransOut(*out) trans_in_pb = _pack_pb_msg(trans_in, wrapped_model.transform._module) trans_out_pb = _pack_pb_msg(trans_out, wrapped_model.transform._module) trans_in_pb_bytes = trans_in_pb.SerializeToString() trans_out_pb_bytes = trans_out_pb.SerializeToString() trans_in_dict = MessageToDict(trans_in_pb) trans_out_dict = MessageToDict(trans_out_pb) trans_in_json = MessageToJson(trans_in_pb, indent=0) trans_out_json = MessageToJson(trans_out_pb, indent=0) # test all from / as combinations for as_method_name, as_data_expected, eq_func in ( ('as_wrapped', trans_out, wrapped_eq), ('as_pb_msg', trans_out_pb, pb_mg_eq), ('as_pb_bytes', trans_out_pb_bytes, pb_bytes_eq), ('as_dict', trans_out_dict, dict_eq), ('as_json', trans_out_json, json_eq)): for from_method_name, from_data in (('from_wrapped', trans_in), ('from_pb_msg', trans_in_pb), ('from_pb_bytes', trans_in_pb_bytes), ('from_dict', trans_in_dict), ('from_json', trans_in_json)): if skip is not None and skip(as_method_name, from_method_name): logger.info("Skipping {} -> {}".format( from_method_name, as_method_name)) continue from_method = getattr(wrapped_model.transform, from_method_name) resp = from_method(from_data) as_data_method = getattr(resp, as_method_name) as_data = as_data_method() assert eq_func(as_data, as_data_expected)
def main(config={}): import argparse from image_mood_classifier.prediction_formatter import Formatter from image_mood_classifier._version import MODEL_NAME parser = argparse.ArgumentParser() submain = parser.add_argument_group('main execution and evaluation functionality') submain.add_argument('-p', '--predict_path', type=str, default='', help="Save predictions from model (model must be provided via 'dump_model')") submain.add_argument('-i', '--input', type=str, default='', help='Absolute path to input training data file. (for now must be a header-less CSV)') submain.add_argument('-C', '--cuda_env', type=str, default='', help='Anything special to inject into CUDA_VISIBLE_DEVICES environment string') subopts = parser.add_argument_group('model creation and configuration options') subopts.add_argument('-l', '--labels', type=str, default='', help="Path to label one-column file with one row for each input") subopts.add_argument('-m', '--model_type', type=str, default='rf', help='specify the underlying classifier type (rf (randomforest), svc (SVM))', choices=['svm', 'rf']) subopts.add_argument('-f', '--feature_nomask', dest='feature_nomask', default=False, action='store_true', help='create masked samples on input') subopts.add_argument('-n', '--add_softnoise', dest='softnoise', default=False, action='store_true', help='do not add soft noise to classification inputs') subopts.add_argument('-a', '--push_address', help='server address to push the model (e.g. http://localhost:8887/upload)', default=os.getenv('ACUMOS_PUSH', "")) subopts.add_argument('-A', '--auth_address', help='server address for login and push of the model (e.g. http://localhost:8887/auth)', default=os.getenv('ACUMOS_AUTH', "")) subopts.add_argument('-d', '--dump_model', help='dump model to a pickle directory for local running', default='') subopts.add_argument('-s', '--summary', type=int, dest='summary', default=0, help='summarize top N image classes are strong for which label class (only in training)') config.update(vars(parser.parse_args())) # pargs, unparsed = parser.parse_known_args() if not os.path.exists(config['input']): print("The target input '{:}' was not found, please check input arguments.".format(config['input'])) sys.exit(-1) print("Loading raw samples...") rawDf = pd.read_csv(config['input'], delimiter=",") # If you want to use a GPU set its index here if config['cuda_env']: os.environ['CUDA_VISIBLE_DEVICES'] = config['cuda_env'] if not config['predict_path'] and config['labels']: if not os.path.exists(config['labels']): print("The target labels '{:}' was not found, please check input arguments.".format(config['labels'])) sys.exit(-1) # refactor the raw samples from upstream image classifier print("=================input_softnoise=config['softnoise']:%s",config['softnoise']) formatter = Formatter(input_softnoise=config['softnoise']) print("=======================formater:%s", formatter) print("Loading labels to train a new model...") rawLabel = pd.read_csv(config['labels'], header=None, delimiter=",") if len(rawLabel.columns) != 1: print("Error, not currently programmed to best-of class selection to a singleton.") sys.exit(-1) rawLabel = rawLabel[0].tolist() formatter.learn_input_mapping(rawDf, "tag", "image", "score") print("=======================formater:%s", formatter) print("Converting block of {:} responses into training data, utilizing {:} images...".format(len(rawDf), len(rawLabel))) objRefactor = formatter.transform_raw_sample(rawDf, rawLabel, None if config['feature_nomask'] else Formatter.SAMPLE_GENERATE_MASKING) print("Generated {:} total samples (skip-masking: {:})".format(len(objRefactor['values']), config['feature_nomask'])) clf = model_archive() # debug helper # run summary? if config['summary']: df_combined = pd.DataFrame(objRefactor['values'], columns=objRefactor['columns']) df_combined['_labels'] = objRefactor['labels'] groupSet = df_combined.groupby('_labels') for nameG, rowsG in groupSet: df_sum = rowsG.sum(axis=0, numeric_only=True) series_top = df_sum.sort_values(ascending=False) print("Label: '{:}', top {:} classes...".format(nameG, config['summary'])) print(series_top[0:config['summary']]) # create pipeline to dump via client library if config['push_address'] or config['dump_model']: if clf is None: clf = classifier_train(objRefactor['values'], objRefactor['labels'], config['model_type']) model, reqs = model_create_pipeline(formatter, clf) model_archive(clf) # debug helper # formulate the pipeline to be used if config['push_address']: from acumos.session import AcumosSession session = AcumosSession(push_api=config['push_address'], auth_api=config['auth_address']) session.push(model, MODEL_NAME, reqs) # creates ./my-iris.zip print("Pushing new model to '{:}'...".format(config['push_address'])) if config['dump_model']: from acumos.session import AcumosSession from os import makedirs if not os.path.exists(config['dump_model']): makedirs(config['dump_model']) print("Dumping new model to '{:}'...".format(config['dump_model'])) session = AcumosSession() session.dump(model, MODEL_NAME, config['dump_model'], reqs) # creates ./my-iris.zip else: if not config['dump_model'] or not os.path.exists(config['dump_model']): print("Attempting to predict from a dumped model, but model not found.".format(config['dump_model'])) sys.exit(-1) print("Attempting predict/transform on input sample...") from acumos.wrapped import load_model model = load_model(config['dump_model']) type_in = model.classify._input_type classify_in = type_in(*tuple(col for col in rawDf.values.T)) out_wrapped = model.classify.from_wrapped(classify_in).as_wrapped() # for now, peel out top sample from classify set dfPred = pd.DataFrame(out_wrapped[0]) if config['predict_path']: print("Writing prediction to file '{:}'...".format(config['predict_path'])) dfPred.to_csv(config['predict_path'], sep=",", index=False) if dfPred is not None: print("Predictions:\n{:}".format(dfPred))
def keras_evaluate(config): taskComplete = False useSklearn = True listImages = [] if 'image_list' in config and config['image_list']: dfImages = pd.read_csv(config['image_list'], header=None, names=['file'], delimiter=",") listImages = dfImages['file'].tolist() config['image'] = listImages[0] X = create_sample(config['image']) if useSklearn: # formulate the pipelien to be used from image_classifier.keras_model.prediction_formatter import Formatter model, reqs = model_create_pipeline(config['model_path'], config['label_path'], config['num_top_predictions']) if 'push_address' in config and 'auth_address' in config and config['push_address']: from acumos.session import AcumosSession session = AcumosSession(push_api=config['push_address'], auth_api=config['auth_address']) print("Pushing new model to upload '{:}', auth '{:}'...".format(config['push_address'], config['auth_address'])) session.push(model, MODEL_NAME, reqs) # creates ./my-iris.zip taskComplete = True if 'dump_model' in config and config['dump_model']: from acumos.session import AcumosSession from os import makedirs if not os.path.exists(config['dump_model']): makedirs(config['dump_model']) print("Dumping new model to '{:}'...".format(config['dump_model'])) session = AcumosSession() session.dump(model, MODEL_NAME, config['dump_model'], reqs) # creates ./my-iris.zip taskComplete = True preds = None if not taskComplete: # means we need to run a prediction/classify import tempfile from acumos.session import _dump_model, _copy_dir from os.path import join as path_join from acumos.wrapped import load_model if not listImages: listImages = [config['image']] preds = None # temporarily wrap model to a temp directory (to get 'wrapped' functionality) with tempfile.TemporaryDirectory() as tdir: # create temp dir with _dump_model(model, MODEL_NAME, reqs) as dump_dir: # dump model to temp dir _copy_dir(dump_dir, tdir, MODEL_NAME) # relocate for load_model below model_dir = path_join(tdir, MODEL_NAME) wrapped_model = load_model(model_dir) # load to wrapped model type_in = wrapped_model.classify._input_type for idx in range(len(listImages)): curImage = listImages[idx] print("Attempting classification of image [{:}]: {:}...".format(idx, curImage)) X = create_sample(curImage) classify_in = type_in(*tuple(col for col in X.values.T)) pred_raw = wrapped_model.classify.from_wrapped(classify_in).as_wrapped() # already a wrapped response predNew = pd.DataFrame(np.column_stack(pred_raw), columns=pred_raw._fields) predNew[Formatter.COL_NAME_IDX] = idx if preds is None: preds = predNew else: preds = preds.append(predNew, ignore_index=True) preds.reset_index(drop=True, inplace=True) """ Disable non-sklearn path for now else: from image_classifier.keras import inception_v4 from image_classifier.keras.image_decoder import ImageDecoder # Load test image! img = ImageDecoder.get_processed_image_keras_file(config['image']) # load image through keras # img = evaluate_image.get_processed_image_cv(config['image']) # Run prediction on test image model, model_path = inception_v4.create_model(weights='imagenet', include_top=True, model_path=model_path) preds = model.predict(img) """ return preds
# 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========================================================= # -*- coding: utf-8 -*- """ Loads a dumped model """ import sys from acumos.wrapped import load_model if __name__ == '__main__': '''Main''' del sys.path[0] # remove acumos/tests dir from python path model_dir = sys.argv[1] module_name = sys.argv[2] model = load_model(model_dir) custom_package = sys.modules[module_name] # `module_name` should be imported, else KeyError
''' Provides a "listener" application that listens for Prediction messages ''' import argparse from flask import Flask, request from acumos.wrapped import load_model if __name__ == '__main__': '''Main''' parser = argparse.ArgumentParser() parser.add_argument("--port", type=int, default=3331) parser.add_argument("--modeldir", type=str, default='model') pargs = parser.parse_args() model = load_model(pargs.modeldir) Prediction = model.transform.pb_output_type # need the Prediction message definition to deserialize app = Flask(__name__) @app.route('/listen', methods=['POST']) def listen(): bytes_in = request.data msg = Prediction.FromString(bytes_in) print("Received Prediction message: {}".format(msg.predictions)) return 'OK', 201 print("Running Flask server on port {:}".format(pargs.port)) app.run(port=pargs.port)