예제 #1
0
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
예제 #2
0
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)
예제 #3
0
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
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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)
예제 #9
0
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)
예제 #10
0
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
예제 #13
0
'''
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)