├── dev-requirements.txt ├── benchmark ├── benchmark-requirements.txt ├── ray_deploy.py ├── locustfile.py ├── fastapi_main_load_model.py ├── fastapi_main_local_runner.py ├── README.md ├── service.py ├── service_local_runner.py └── sample.py ├── train.sh ├── submit_test_requests.sh ├── bentofile.yaml ├── inference_graph_demo ├── bentofile.yaml ├── service.py └── sample.py ├── download_data.sh ├── bentofile-gpu.yaml ├── service.py ├── .gitignore ├── README.md ├── sample.py └── LICENSE /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | notebook 2 | kaggle 3 | jupyter 4 | numpy 5 | pandas 6 | xgboost 7 | scikit-learn 8 | nbconvert 9 | -------------------------------------------------------------------------------- /benchmark/benchmark-requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | pandas 3 | xgboost 4 | scikit-learn 5 | fastapi 6 | uvicorn[standard] 7 | locust 8 | -------------------------------------------------------------------------------- /train.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | jupyter nbconvert --to notebook --inplace --execute ./IEEE-CIS-Fraud-Detection.ipynb --debug 2>&1 | grep -v '^\[NbConvertApp\]' 4 | -------------------------------------------------------------------------------- /submit_test_requests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | head --lines=200 ./data/test_transaction.csv | curl -X POST -H 'Content-Type: text/csv' --data-binary @- http://0.0.0.0:3000/is_fraud 4 | -------------------------------------------------------------------------------- /bentofile.yaml: -------------------------------------------------------------------------------- 1 | service: "service:svc" 2 | include: 3 | - "service.py" 4 | - "sample.py" 5 | python: 6 | packages: 7 | - numpy 8 | - pandas 9 | - xgboost 10 | - scikit-learn 11 | -------------------------------------------------------------------------------- /inference_graph_demo/bentofile.yaml: -------------------------------------------------------------------------------- 1 | service: "inference_graph_service:svc" 2 | include: 3 | - "*.py" 4 | python: 5 | packages: 6 | - numpy 7 | - pandas 8 | - xgboost 9 | - scikit-learn 10 | -------------------------------------------------------------------------------- /download_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -ex 4 | 5 | kaggle competitions download -c ieee-fraud-detection 6 | rm -rf ./data/ 7 | unzip -o -d ./data/ ieee-fraud-detection.zip && rm ieee-fraud-detection.zip 8 | -------------------------------------------------------------------------------- /bentofile-gpu.yaml: -------------------------------------------------------------------------------- 1 | service: "service:svc" 2 | include: 3 | - "service.py" 4 | - "sample.py" 5 | docker: 6 | cuda_version: "11.6.2" 7 | python: 8 | packages: 9 | - numpy 10 | - pandas 11 | - xgboost 12 | - scikit-learn 13 | -------------------------------------------------------------------------------- /benchmark/ray_deploy.py: -------------------------------------------------------------------------------- 1 | import bentoml 2 | 3 | deploy = bentoml.ray.deployment( 4 | "fraud_detection:latest", 5 | {"num_replicas": 5, "ray_actor_options": {"num_cpus": 1}}, 6 | { 7 | "ieee-fraud-detection-sm": { 8 | "num_replicas": 1, 9 | "ray_actor_options": {"num_cpus": 5}, 10 | } 11 | }, 12 | enable_batching=True, 13 | batching_config={ 14 | "ieee-fraud-detection-sm": { 15 | "predict_proba": {"max_batch_size": 5, "batch_wait_timeout_s": 0.2} 16 | } 17 | }, 18 | ) 19 | -------------------------------------------------------------------------------- /benchmark/locustfile.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from locust import task 4 | from locust import between 5 | from locust import HttpUser 6 | 7 | NUM_OF_ROWS = 500 8 | test_transactions = pd.read_csv("../data/test_transaction.csv")[0:NUM_OF_ROWS] 9 | 10 | endpoint = "/is_fraud" 11 | # endpoint = "/is_fraud_async" 12 | 13 | 14 | class FraudDetectionUser(HttpUser): 15 | @task 16 | def is_fraud(self): 17 | index = np.random.choice(NUM_OF_ROWS) 18 | input_data = test_transactions[index : index + 1] 19 | self.client.post(endpoint, data=input_data.to_json()) 20 | 21 | wait_time = between(0.01, 2) 22 | -------------------------------------------------------------------------------- /service.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sample import sample_input 4 | 5 | import bentoml 6 | from bentoml.io import JSON 7 | from bentoml.io import PandasDataFrame 8 | 9 | model_ref = bentoml.xgboost.get("ieee-fraud-detection-lg:latest") 10 | preprocessor = model_ref.custom_objects["preprocessor"] 11 | fraud_model_runner = model_ref.to_runner() 12 | 13 | svc = bentoml.Service("fraud_detection", runners=[fraud_model_runner]) 14 | 15 | input_spec = PandasDataFrame.from_sample(sample_input) 16 | 17 | 18 | @svc.api(input=input_spec, output=JSON()) 19 | async def is_fraud(input_df: pd.DataFrame): 20 | input_df = input_df.astype(sample_input.dtypes) 21 | input_features = preprocessor.transform(input_df) 22 | results = await fraud_model_runner.predict_proba.async_run(input_features) 23 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 24 | return {"is_fraud": list(map(bool, predictions)), "is_fraud_prob": results[:, 1]} 25 | -------------------------------------------------------------------------------- /benchmark/fastapi_main_load_model.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from sample import sample_input 6 | from fastapi import FastAPI 7 | from fastapi import Request 8 | 9 | import bentoml 10 | 11 | model_tag = "ieee-fraud-detection-lg:latest" 12 | preprocessor = bentoml.xgboost.get(model_tag).custom_objects["preprocessor"] 13 | fraud_model = bentoml.xgboost.load_model(model_tag) 14 | 15 | app = FastAPI() 16 | 17 | 18 | @app.post("/is_fraud") 19 | async def is_fraud(request: Request): 20 | body = await request.body() 21 | input_df = pd.read_json(io.BytesIO(body), dtype=True, orient="records") 22 | input_df = input_df.astype(sample_input.dtypes) 23 | input_features = preprocessor.transform(input_df) 24 | results = fraud_model.predict_proba(input_features) 25 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 26 | return { 27 | "is_fraud": list(map(bool, predictions)), 28 | "is_fraud_prob": results[:, 1].tolist(), 29 | } 30 | -------------------------------------------------------------------------------- /benchmark/fastapi_main_local_runner.py: -------------------------------------------------------------------------------- 1 | import io 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from sample import sample_input 6 | from fastapi import FastAPI 7 | from fastapi import Request 8 | 9 | import bentoml 10 | 11 | model_ref = bentoml.xgboost.get("ieee-fraud-detection-lg:latest") 12 | preprocessor = model_ref.custom_objects["preprocessor"] 13 | fraud_model_runner = model_ref.to_runner() 14 | fraud_model_runner.init_local() 15 | 16 | app = FastAPI() 17 | 18 | 19 | @app.post("/is_fraud") 20 | async def is_fraud(request: Request): 21 | body = await request.body() 22 | input_df = pd.read_json(io.BytesIO(body), dtype=True, orient="records") 23 | input_df = input_df.astype(sample_input.dtypes) 24 | input_features = preprocessor.transform(input_df) 25 | results = await fraud_model_runner.predict_proba.async_run(input_features) 26 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 27 | return { 28 | "is_fraud": list(map(bool, predictions)), 29 | "is_fraud_prob": results[:, 1].tolist(), 30 | } 31 | -------------------------------------------------------------------------------- /benchmark/README.md: -------------------------------------------------------------------------------- 1 | # Benchmark 2 | 3 | 1. Install dependencies: 4 | ```bash 5 | pip install -r ./dev-requirements.txt 6 | ``` 7 | 8 | 2. Benchmark with Locust 9 | ```bash 10 | bentoml serve service:svc --production 11 | ``` 12 | ```bash 13 | locust -H http://0.0.0.0:3000 -u 200 -r 10 14 | ``` 15 | 16 | Visit http://0.0.0.0:8089/ and start the test. 17 | 18 | 3. Testing other serving methods 19 | 20 | * BentoML with distributed Runner architecture (default, recommended for most use cases) 21 | ```bash 22 | bentoml serve service:svc --production 23 | ``` 24 | 25 | * BentoML with embedded local Runner (recommended for light-weight models) 26 | ```bash 27 | bentoml serve service_local_runner:svc --production 28 | ``` 29 | 30 | * A typical FastAPI implementation with XGBoost syncrounous API for inference: 31 | 32 | ```bash 33 | uvicorn fastapi_main_load_model:app --workers=10 --port=3000 34 | ``` 35 | 36 | * FastAPI endpoint with BentoML runner async API for inference: 37 | 38 | ```bash 39 | uvicorn fastapi_main_local_runner:app --workers=10 --port=3000 40 | ``` 41 | 42 | * BentoML deployed on Ray 43 | 44 | serve run ray_deploy:deploy -p 3000 45 | -------------------------------------------------------------------------------- /benchmark/service.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sample import sample_input 4 | 5 | import bentoml 6 | from bentoml.io import JSON 7 | from bentoml.io import PandasDataFrame 8 | 9 | model_ref = bentoml.xgboost.get("ieee-fraud-detection-lg:latest") 10 | preprocessor = model_ref.custom_objects["preprocessor"] 11 | fraud_model_runner = model_ref.to_runner() 12 | 13 | svc = bentoml.Service("fraud_detection", runners=[fraud_model_runner]) 14 | 15 | input_spec = PandasDataFrame.from_sample(sample_input) 16 | 17 | 18 | @svc.api(input=input_spec, output=JSON()) 19 | def is_fraud(input_df: pd.DataFrame): 20 | input_df = input_df.astype(sample_input.dtypes) 21 | input_features = preprocessor.transform(input_df) 22 | results = fraud_model_runner.predict_proba.run(input_features) 23 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 24 | return {"is_fraud": list(map(bool, predictions)), "is_fraud_prob": results[:, 1]} 25 | 26 | 27 | @svc.api(input=input_spec, output=JSON()) 28 | async def is_fraud_async(input_df: pd.DataFrame): 29 | input_df = input_df.astype(sample_input.dtypes) 30 | input_features = preprocessor.transform(input_df) 31 | results = await fraud_model_runner.predict_proba.async_run(input_features) 32 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 33 | return {"is_fraud": list(map(bool, predictions)), "is_fraud_prob": results[:, 1]} 34 | -------------------------------------------------------------------------------- /benchmark/service_local_runner.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import pandas as pd 3 | from sample import sample_input 4 | 5 | import bentoml 6 | from bentoml.io import JSON 7 | from bentoml.io import PandasDataFrame 8 | 9 | model_ref = bentoml.xgboost.get("ieee-fraud-detection-lg:latest") 10 | preprocessor = model_ref.custom_objects["preprocessor"] 11 | fraud_model_runner = model_ref.to_runner() 12 | fraud_model_runner.init_local() 13 | 14 | svc = bentoml.Service("fraud_detection") 15 | 16 | input_spec = PandasDataFrame.from_sample(sample_input) 17 | 18 | 19 | @svc.api(input=input_spec, output=JSON()) 20 | def is_fraud(input_df: pd.DataFrame): 21 | input_df = input_df.astype(sample_input.dtypes) 22 | input_features = preprocessor.transform(input_df) 23 | results = fraud_model_runner.predict_proba.run(input_features) 24 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 25 | return {"is_fraud": list(map(bool, predictions)), "is_fraud_prob": results[:, 1]} 26 | 27 | 28 | @svc.api(input=input_spec, output=JSON()) 29 | async def is_fraud_async(input_df: pd.DataFrame): 30 | input_df = input_df.astype(sample_input.dtypes) 31 | input_features = preprocessor.transform(input_df) 32 | results = await fraud_model_runner.predict_proba.async_run(input_features) 33 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 34 | return {"is_fraud": list(map(bool, predictions)), "is_fraud_prob": results[:, 1]} 35 | -------------------------------------------------------------------------------- /inference_graph_demo/service.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | import numpy as np 4 | import pandas as pd 5 | from sample import sample_input 6 | 7 | import bentoml 8 | from bentoml.io import JSON 9 | from bentoml.io import PandasDataFrame 10 | 11 | model_ref = bentoml.xgboost.get("ieee-fraud-detection-lg:latest") 12 | preprocessor = model_ref.custom_objects["preprocessor"] 13 | 14 | fraud_model_tiny_runner = bentoml.xgboost.get( 15 | "ieee-fraud-detection-tiny:latest" 16 | ).to_runner() 17 | fraud_model_small_runner = bentoml.xgboost.get( 18 | "ieee-fraud-detection-sm:latest" 19 | ).to_runner() 20 | fraud_model_large_runner = bentoml.xgboost.get( 21 | "ieee-fraud-detection-lg:latest" 22 | ).to_runner() 23 | 24 | svc = bentoml.Service( 25 | "fraud_detection_inference_graph", 26 | runners=[ 27 | fraud_model_tiny_runner, 28 | fraud_model_small_runner, 29 | fraud_model_large_runner, 30 | ], 31 | ) 32 | 33 | input_spec = PandasDataFrame.from_sample(sample_input) 34 | 35 | 36 | async def _is_fraud_async( 37 | runner: bentoml.Runner, 38 | input_df: pd.DataFrame, 39 | ): 40 | results = await runner.predict_proba.async_run(input_df) 41 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 42 | return {"is_fraud": list(map(bool, predictions)), "is_fraud_prob": results[:, 1]} 43 | 44 | 45 | @svc.api(input=input_spec, output=JSON()) 46 | async def is_fraud(input_df: pd.DataFrame): 47 | input_df = input_df.astype(sample_input.dtypes) 48 | input_df = preprocessor.transform(input_df) 49 | return await asyncio.gather( 50 | _is_fraud_async(fraud_model_tiny_runner, input_df), 51 | _is_fraud_async(fraud_model_small_runner, input_df), 52 | _is_fraud_async(fraud_model_large_runner, input_df), 53 | ) 54 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # pdm 105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 106 | #pdm.lock 107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 108 | # in version control. 109 | # https://pdm.fming.dev/#use-with-ide 110 | .pdm.toml 111 | 112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 113 | __pypackages__/ 114 | 115 | # Celery stuff 116 | celerybeat-schedule 117 | celerybeat.pid 118 | 119 | # SageMath parsed files 120 | *.sage.py 121 | 122 | # Environments 123 | .env 124 | .venv 125 | env/ 126 | venv/ 127 | ENV/ 128 | env.bak/ 129 | venv.bak/ 130 | 131 | # Spyder project settings 132 | .spyderproject 133 | .spyproject 134 | 135 | # Rope project settings 136 | .ropeproject 137 | 138 | # mkdocs documentation 139 | /site 140 | 141 | # mypy 142 | .mypy_cache/ 143 | .dmypy.json 144 | dmypy.json 145 | 146 | # Pyre type checker 147 | .pyre/ 148 | 149 | # pytype static type analyzer 150 | .pytype/ 151 | 152 | # Cython debug symbols 153 | cython_debug/ 154 | 155 | # PyCharm 156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 158 | # and can be added to the global gitignore or merged into this file. For a more nuclear 159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 160 | #.idea/ 161 | 162 | data/ 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |

Fraud Detection Models Serving

3 |
4 | Online model serving with Fraud Detection model trained with XGBoost on IEEE-CIS dataset
5 | Powered by BentoML 🍱 6 |
7 |
8 |
9 | 10 | ## 📖 Introduction 📖 11 | This project demonstrates how to serve a fraud detection model trained with [XGBoost]() on the 12 | dataset from the [IEEE-CIS Fraud Detection competition](https://www.kaggle.com/competitions/ieee-fraud-detection/data). 13 | 14 | 15 | ## 🏃‍♂️ Getting Started 🏃‍♂️ 16 | 17 | ### 0. Clone the Repository: 18 | 19 | ```bash 20 | git clone git@github.com:bentoml/Fraud-Detection-Model-Serving.git 21 | cd Fraud-Detection-Model-Serving 22 | ``` 23 | 24 | ### 1. Install Dependencies: 25 | ```bash 26 | pip install -r ./dev-requirements.txt 27 | ``` 28 | 29 | ### 2. Download dataset 30 | 31 | Before downloading, set up your Kaggle API Credentials following instructions 32 | [here](https://github.com/Kaggle/kaggle-api#api-credentials) and accept the [dataset 33 | rules on Kaggle](https://www.kaggle.com/competitions/ieee-fraud-detection/data) 34 | 35 | ```bash 36 | ./download_data.sh 37 | ``` 38 | 39 | ### 3. Model Training 40 | 41 | Execute the `./IEEE-CIS-Fraud-Detection.ipynb` notebook with the `train.sh` script: 42 | ```bash 43 | ./train.sh 44 | ``` 45 | 46 | This will create 3 variations of the model, you can view and manage those models via the 47 | `bentoml models` CLI commnad: 48 | 49 | ```bash 50 | $ bentoml models list 51 | 52 | Tag Module Size Creation Time 53 | ieee-fraud-detection-tiny:qli6n3f6jcta3uqj bentoml.xgboost 141.40 KiB 2023-03-08 23:03:36 54 | ieee-fraud-detection-lg:o7wqb5f6jcta3uqj bentoml.xgboost 18.07 MiB 2023-03-08 23:03:17 55 | ieee-fraud-detection-sm:5yblgmf6i2ta3uqj bentoml.xgboost 723.00 KiB 2023-03-08 22:52:16 56 | ``` 57 | 58 | Saved models can also be accessed via the BentoML Python API, e.g.: 59 | 60 | ```python 61 | import bentoml 62 | import pandas as pd 63 | import numpy as np 64 | 65 | model_ref = bentoml.xgboost.get("ieee-fraud-detection-sm:latest") 66 | model_runner = model_ref.to_runner() 67 | model_runner.init_local() 68 | model_preprocessor = model_ref.custom_objects["preprocessor"] 69 | 70 | test_transactions = pd.read_csv("./data/test_transaction.csv")[0:500] 71 | test_transactions = model_preprocessor.transform(test_transactions) 72 | result = model_runner.predict_proba.run(test_transactions) 73 | print(np.argmax(result, axis=1)) 74 | ``` 75 | 76 | 77 | ### 4. Serving the model 78 | 79 | The `service.py` file contains the source code for defining an ML service: 80 | 81 | ```python 82 | import numpy as np 83 | import pandas as pd 84 | from sample import sample_input 85 | 86 | import bentoml 87 | from bentoml.io import JSON 88 | from bentoml.io import PandasDataFrame 89 | 90 | model_ref = bentoml.xgboost.get("ieee-fraud-detection-lg:latest") 91 | preprocessor = model_ref.custom_objects["preprocessor"] 92 | fraud_model_runner = model_ref.to_runner() 93 | 94 | svc = bentoml.Service("fraud_detection", runners=[fraud_model_runner]) 95 | 96 | input_spec = PandasDataFrame.from_sample(sample_input) 97 | 98 | @svc.api(input=input_spec, output=JSON()) 99 | async def is_fraud(input_df: pd.DataFrame): 100 | input_df = input_df.astype(sample_input.dtypes) 101 | input_features = preprocessor.transform(input_df) 102 | results = await fraud_model_runner.predict_proba.async_run(input_features) 103 | predictions = np.argmax(results, axis=1) # 0 is not fraud, 1 is fraud 104 | return {"is_fraud": list(map(bool, predictions)), "is_fraud_prob": results[:, 1]} 105 | ``` 106 | 107 | 108 | Run `bentoml serve` command to launch the server locally: 109 | 110 | ```bash 111 | bentoml serve 112 | ``` 113 | 114 | ## 🌐 Interacting with the Service 🌐 115 | The default mode of BentoML's model serving is via HTTP server. Here, we showcase a few examples of how one can interact with the service: 116 | ### Swagger UI 117 | Visit `http://localhost:3000/` in a browser and send test requests via the UI. 118 | 119 | ### cURL 120 | Via the command `curl`, you can: 121 | ```bash 122 | head --lines=200 ./data/test_transaction.csv | curl -X POST -H 'Content-Type: text/csv' --data-binary @- http://0.0.0.0:3000/is_fraud 123 | ``` 124 | 125 | ### Via BentoClient 🐍 126 | ```python 127 | import pandas as pd 128 | from bentoml.client import Client 129 | 130 | test_transactions = pd.read_csv("./data/test_transaction.csv")[0:500] 131 | client = Client.from_url('localhost:3000') 132 | 133 | results = client.is_fraud(test_transaction) 134 | print(results) 135 | ``` 136 | 137 | 138 | ## 🚀 Deploying to Production 🚀 139 | Effortlessly transition your project into a production-ready application using [BentoCloud](https://www.bentoml.com/bento-cloud/), the production-ready platform for managing and deploying machine learning models. 140 | 141 | Start by creating a BentoCloud account. Once you've signed up, log in to your BentoCloud account using the command: 142 | 143 | ```bash 144 | bentoml cloud login --api-token --endpoint 145 | ``` 146 | > Note: Replace `` and `` with your specific API token and the BentoCloud endpoint respectively. 147 | 148 | Next, build your BentoML service using the `build` command: 149 | 150 | ```bash 151 | bentoml build 152 | ``` 153 | 154 | Then, push your freshly-built Bento service to BentoCloud using the `push` command: 155 | 156 | ```bash 157 | bentoml push 158 | ``` 159 | 160 | Lastly, deploy this application to BentoCloud with a single `bentoml deployment create` command following the [deployment instructions](https://docs.bentoml.org/en/latest/reference/cli.html#bentoml-deployment-create). 161 | 162 | BentoML offers a number of options for deploying and hosting online ML services into production, learn more at [Deploying a Bento](https://docs.bentoml.org/en/latest/concepts/deploy.html). 163 | 164 | --- 165 | 166 | In this README, we will also go over a basic deployment strategy with Docker containers. 167 | 168 | 169 | ### 1. Build a docker image 170 | 171 | Build a Bento to lock the model version and dependency tree: 172 | ```bash 173 | bentoml build 174 | ``` 175 | 176 | Ensure docker is installed and running, build a docker image with `bentoml containerize` 177 | ```bash 178 | bentoml containerize fraud_detection:latest 179 | ``` 180 | 181 | Test out the docker image built: 182 | 183 | ```bash 184 | docker run -it --rm -p 3000:3000 fraud_detection:{YOUR BENTO VERSION} 185 | ``` 186 | 187 | ### 2. Inference on GPU 188 | 189 | Use `bentofile-gpu.yaml` to build a new Bento, which adds the following two lines to the YAML. 190 | This ensures the docker image comes with GPU libraries installed and BentoML will automatically 191 | load models on GPU when running the docker image with GPU devices available. 192 | 193 | ```yaml 194 | docker: 195 | cuda_version: "11.6.2" 196 | ``` 197 | 198 | Build Bento with GPU support: 199 | ```bash 200 | bentoml build -f ./bentofile-gpu.yaml 201 | ``` 202 | 203 | Build and run docker image with GPU enabled: 204 | ```bash 205 | bentoml containerize fraud_detection:latest 206 | 207 | docker run --gpus all --device /dev/nvidia0 \ 208 | --device /dev/nvidia-uvm --device /dev/nvidia-uvm-tools \ 209 | --device /dev/nvidia-modeset --device /dev/nvidiactl \ 210 | fraud_detection:{YOUR BENTO VERSION} 211 | ``` 212 | 213 | ### 3. Multi-model Inference Pipeline/Graph 214 | 215 | BentoML makes it efficient to create ML service with multiple ML models, which is often used for combining 216 | multiple fraud detection models and getting an aggregated result. With BentoML, users can choose to run 217 | models sequentially or in parallel using the Python AsyncIO APIs along with Runners APIs. This makes 218 | it possible create inference graphes or multi-stage inference pipeline all from Python APIs. 219 | 220 | An example can be found under `inference_graph_demo` that runs all three models simutaneously and 221 | aggregate their results: 222 | 223 | ```bash 224 | cd inference_graph_demo 225 | 226 | bentoml serve 227 | ``` 228 | 229 | Learn more about BentoML Runner usage [here](https://docs.bentoml.org/en/latest/concepts/runner.html) 230 | 231 | 232 | ### 4. Benchmark Testing 233 | 234 | Visit the `/benchmark/README.md` for how to run benchmark tests on your fraud detection service and 235 | understanding its throughput and latency on your deployment target. 236 | 237 | 238 | ## 👥Join our Community 👥 239 | 240 | BentoML has a thriving open source community where thousands of ML/AI practitioners are contributing to the project, helping other users and discussing the future of AI. [👉 Join us on slack today!](https://l.bentoml.com/join-slack) 241 | -------------------------------------------------------------------------------- /sample.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | sample_json = [ 4 | { 5 | "TransactionID": 2987000, 6 | "TransactionDT": 86400, 7 | "TransactionAmt": 68.5, 8 | "ProductCD": "W", 9 | "card1": 13926, 10 | "card2": None, 11 | "card3": 150.0, 12 | "card4": "discover", 13 | "card5": 142.0, 14 | "card6": "credit", 15 | "addr1": 315.0, 16 | "addr2": 87.0, 17 | "dist1": 19.0, 18 | "dist2": None, 19 | "P_emaildomain": None, 20 | "R_emaildomain": None, 21 | "C1": 1.0, 22 | "C2": 1.0, 23 | "C3": 0.0, 24 | "C4": 0.0, 25 | "C5": 0.0, 26 | "C6": 1.0, 27 | "C7": 0.0, 28 | "C8": 0.0, 29 | "C9": 1.0, 30 | "C10": 0.0, 31 | "C11": 2.0, 32 | "C12": 0.0, 33 | "C13": 1.0, 34 | "C14": 1.0, 35 | "D1": 14.0, 36 | "D2": None, 37 | "D3": 13.0, 38 | "D4": None, 39 | "D5": None, 40 | "D6": None, 41 | "D7": None, 42 | "D8": None, 43 | "D9": None, 44 | "D10": 13.0, 45 | "D11": 13.0, 46 | "D12": None, 47 | "D13": None, 48 | "D14": None, 49 | "D15": 0.0, 50 | "M1": "T", 51 | "M2": "T", 52 | "M3": "T", 53 | "M4": "M2", 54 | "M5": "F", 55 | "M6": "T", 56 | "M7": None, 57 | "M8": None, 58 | "M9": None, 59 | "V1": 1.0, 60 | "V2": 1.0, 61 | "V3": 1.0, 62 | "V4": 1.0, 63 | "V5": 1.0, 64 | "V6": 1.0, 65 | "V7": 1.0, 66 | "V8": 1.0, 67 | "V9": 1.0, 68 | "V10": 0.0, 69 | "V11": 0.0, 70 | "V12": 1.0, 71 | "V13": 1.0, 72 | "V14": 1.0, 73 | "V15": 0.0, 74 | "V16": 0.0, 75 | "V17": 0.0, 76 | "V18": 0.0, 77 | "V19": 1.0, 78 | "V20": 1.0, 79 | "V21": 0.0, 80 | "V22": 0.0, 81 | "V23": 1.0, 82 | "V24": 1.0, 83 | "V25": 1.0, 84 | "V26": 1.0, 85 | "V27": 0.0, 86 | "V28": 0.0, 87 | "V29": 0.0, 88 | "V30": 0.0, 89 | "V31": 0.0, 90 | "V32": 0.0, 91 | "V33": 0.0, 92 | "V34": 0.0, 93 | "V35": None, 94 | "V36": None, 95 | "V37": None, 96 | "V38": None, 97 | "V39": None, 98 | "V40": None, 99 | "V41": None, 100 | "V42": None, 101 | "V43": None, 102 | "V44": None, 103 | "V45": None, 104 | "V46": None, 105 | "V47": None, 106 | "V48": None, 107 | "V49": None, 108 | "V50": None, 109 | "V51": None, 110 | "V52": None, 111 | "V53": 1.0, 112 | "V54": 1.0, 113 | "V55": 1.0, 114 | "V56": 1.0, 115 | "V57": 0.0, 116 | "V58": 0.0, 117 | "V59": 0.0, 118 | "V60": 0.0, 119 | "V61": 1.0, 120 | "V62": 1.0, 121 | "V63": 0.0, 122 | "V64": 0.0, 123 | "V65": 1.0, 124 | "V66": 1.0, 125 | "V67": 1.0, 126 | "V68": 0.0, 127 | "V69": 0.0, 128 | "V70": 0.0, 129 | "V71": 0.0, 130 | "V72": 0.0, 131 | "V73": 0.0, 132 | "V74": 0.0, 133 | "V75": 1.0, 134 | "V76": 1.0, 135 | "V77": 1.0, 136 | "V78": 1.0, 137 | "V79": 0.0, 138 | "V80": 0.0, 139 | "V81": 0.0, 140 | "V82": 0.0, 141 | "V83": 0.0, 142 | "V84": 0.0, 143 | "V85": 0.0, 144 | "V86": 1.0, 145 | "V87": 1.0, 146 | "V88": 1.0, 147 | "V89": 0.0, 148 | "V90": 0.0, 149 | "V91": 0.0, 150 | "V92": 0.0, 151 | "V93": 0.0, 152 | "V94": 0.0, 153 | "V95": 0.0, 154 | "V96": 1.0, 155 | "V97": 0.0, 156 | "V98": 0.0, 157 | "V99": 0.0, 158 | "V100": 0.0, 159 | "V101": 0.0, 160 | "V102": 1.0, 161 | "V103": 0.0, 162 | "V104": 0.0, 163 | "V105": 0.0, 164 | "V106": 0.0, 165 | "V107": 1.0, 166 | "V108": 1.0, 167 | "V109": 1.0, 168 | "V110": 1.0, 169 | "V111": 1.0, 170 | "V112": 1.0, 171 | "V113": 1.0, 172 | "V114": 1.0, 173 | "V115": 1.0, 174 | "V116": 1.0, 175 | "V117": 1.0, 176 | "V118": 1.0, 177 | "V119": 1.0, 178 | "V120": 1.0, 179 | "V121": 1.0, 180 | "V122": 1.0, 181 | "V123": 1.0, 182 | "V124": 1.0, 183 | "V125": 1.0, 184 | "V126": 0.0, 185 | "V127": 117.0, 186 | "V128": 0.0, 187 | "V129": 0.0, 188 | "V130": 0.0, 189 | "V131": 0.0, 190 | "V132": 0.0, 191 | "V133": 117.0, 192 | "V134": 0.0, 193 | "V135": 0.0, 194 | "V136": 0.0, 195 | "V137": 0.0, 196 | "V138": None, 197 | "V139": None, 198 | "V140": None, 199 | "V141": None, 200 | "V142": None, 201 | "V143": None, 202 | "V144": None, 203 | "V145": None, 204 | "V146": None, 205 | "V147": None, 206 | "V148": None, 207 | "V149": None, 208 | "V150": None, 209 | "V151": None, 210 | "V152": None, 211 | "V153": None, 212 | "V154": None, 213 | "V155": None, 214 | "V156": None, 215 | "V157": None, 216 | "V158": None, 217 | "V159": None, 218 | "V160": None, 219 | "V161": None, 220 | "V162": None, 221 | "V163": None, 222 | "V164": None, 223 | "V165": None, 224 | "V166": None, 225 | "V167": None, 226 | "V168": None, 227 | "V169": None, 228 | "V170": None, 229 | "V171": None, 230 | "V172": None, 231 | "V173": None, 232 | "V174": None, 233 | "V175": None, 234 | "V176": None, 235 | "V177": None, 236 | "V178": None, 237 | "V179": None, 238 | "V180": None, 239 | "V181": None, 240 | "V182": None, 241 | "V183": None, 242 | "V184": None, 243 | "V185": None, 244 | "V186": None, 245 | "V187": None, 246 | "V188": None, 247 | "V189": None, 248 | "V190": None, 249 | "V191": None, 250 | "V192": None, 251 | "V193": None, 252 | "V194": None, 253 | "V195": None, 254 | "V196": None, 255 | "V197": None, 256 | "V198": None, 257 | "V199": None, 258 | "V200": None, 259 | "V201": None, 260 | "V202": None, 261 | "V203": None, 262 | "V204": None, 263 | "V205": None, 264 | "V206": None, 265 | "V207": None, 266 | "V208": None, 267 | "V209": None, 268 | "V210": None, 269 | "V211": None, 270 | "V212": None, 271 | "V213": None, 272 | "V214": None, 273 | "V215": None, 274 | "V216": None, 275 | "V217": None, 276 | "V218": None, 277 | "V219": None, 278 | "V220": None, 279 | "V221": None, 280 | "V222": None, 281 | "V223": None, 282 | "V224": None, 283 | "V225": None, 284 | "V226": None, 285 | "V227": None, 286 | "V228": None, 287 | "V229": None, 288 | "V230": None, 289 | "V231": None, 290 | "V232": None, 291 | "V233": None, 292 | "V234": None, 293 | "V235": None, 294 | "V236": None, 295 | "V237": None, 296 | "V238": None, 297 | "V239": None, 298 | "V240": None, 299 | "V241": None, 300 | "V242": None, 301 | "V243": None, 302 | "V244": None, 303 | "V245": None, 304 | "V246": None, 305 | "V247": None, 306 | "V248": None, 307 | "V249": None, 308 | "V250": None, 309 | "V251": None, 310 | "V252": None, 311 | "V253": None, 312 | "V254": None, 313 | "V255": None, 314 | "V256": None, 315 | "V257": None, 316 | "V258": None, 317 | "V259": None, 318 | "V260": None, 319 | "V261": None, 320 | "V262": None, 321 | "V263": None, 322 | "V264": None, 323 | "V265": None, 324 | "V266": None, 325 | "V267": None, 326 | "V268": None, 327 | "V269": None, 328 | "V270": None, 329 | "V271": None, 330 | "V272": None, 331 | "V273": None, 332 | "V274": None, 333 | "V275": None, 334 | "V276": None, 335 | "V277": None, 336 | "V278": None, 337 | "V279": 0.0, 338 | "V280": 0.0, 339 | "V281": 0.0, 340 | "V282": 1.0, 341 | "V283": 1.0, 342 | "V284": 0.0, 343 | "V285": 0.0, 344 | "V286": 0.0, 345 | "V287": 0.0, 346 | "V288": 0.0, 347 | "V289": 0.0, 348 | "V290": 1.0, 349 | "V291": 1.0, 350 | "V292": 1.0, 351 | "V293": 0.0, 352 | "V294": 1.0, 353 | "V295": 0.0, 354 | "V296": 0.0, 355 | "V297": 0.0, 356 | "V298": 0.0, 357 | "V299": 0.0, 358 | "V300": 0.0, 359 | "V301": 0.0, 360 | "V302": 0.0, 361 | "V303": 0.0, 362 | "V304": 0.0, 363 | "V305": 1.0, 364 | "V306": 0.0, 365 | "V307": 117.0, 366 | "V308": 0.0, 367 | "V309": 0.0, 368 | "V310": 0.0, 369 | "V311": 0.0, 370 | "V312": 0.0, 371 | "V313": 0.0, 372 | "V314": 0.0, 373 | "V315": 0.0, 374 | "V316": 0.0, 375 | "V317": 117.0, 376 | "V318": 0.0, 377 | "V319": 0.0, 378 | "V320": 0.0, 379 | "V321": 0.0, 380 | "V322": None, 381 | "V323": None, 382 | "V324": None, 383 | "V325": None, 384 | "V326": None, 385 | "V327": None, 386 | "V328": None, 387 | "V329": None, 388 | "V330": None, 389 | "V331": None, 390 | "V332": None, 391 | "V333": None, 392 | "V334": None, 393 | "V335": None, 394 | "V336": None, 395 | "V337": None, 396 | "V338": None, 397 | "V339": None, 398 | } 399 | ] 400 | 401 | sample_input = pd.DataFrame(sample_json) 402 | -------------------------------------------------------------------------------- /benchmark/sample.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | sample_json = [ 4 | { 5 | "TransactionID": 2987000, 6 | "TransactionDT": 86400, 7 | "TransactionAmt": 68.5, 8 | "ProductCD": "W", 9 | "card1": 13926, 10 | "card2": None, 11 | "card3": 150.0, 12 | "card4": "discover", 13 | "card5": 142.0, 14 | "card6": "credit", 15 | "addr1": 315.0, 16 | "addr2": 87.0, 17 | "dist1": 19.0, 18 | "dist2": None, 19 | "P_emaildomain": None, 20 | "R_emaildomain": None, 21 | "C1": 1.0, 22 | "C2": 1.0, 23 | "C3": 0.0, 24 | "C4": 0.0, 25 | "C5": 0.0, 26 | "C6": 1.0, 27 | "C7": 0.0, 28 | "C8": 0.0, 29 | "C9": 1.0, 30 | "C10": 0.0, 31 | "C11": 2.0, 32 | "C12": 0.0, 33 | "C13": 1.0, 34 | "C14": 1.0, 35 | "D1": 14.0, 36 | "D2": None, 37 | "D3": 13.0, 38 | "D4": None, 39 | "D5": None, 40 | "D6": None, 41 | "D7": None, 42 | "D8": None, 43 | "D9": None, 44 | "D10": 13.0, 45 | "D11": 13.0, 46 | "D12": None, 47 | "D13": None, 48 | "D14": None, 49 | "D15": 0.0, 50 | "M1": "T", 51 | "M2": "T", 52 | "M3": "T", 53 | "M4": "M2", 54 | "M5": "F", 55 | "M6": "T", 56 | "M7": None, 57 | "M8": None, 58 | "M9": None, 59 | "V1": 1.0, 60 | "V2": 1.0, 61 | "V3": 1.0, 62 | "V4": 1.0, 63 | "V5": 1.0, 64 | "V6": 1.0, 65 | "V7": 1.0, 66 | "V8": 1.0, 67 | "V9": 1.0, 68 | "V10": 0.0, 69 | "V11": 0.0, 70 | "V12": 1.0, 71 | "V13": 1.0, 72 | "V14": 1.0, 73 | "V15": 0.0, 74 | "V16": 0.0, 75 | "V17": 0.0, 76 | "V18": 0.0, 77 | "V19": 1.0, 78 | "V20": 1.0, 79 | "V21": 0.0, 80 | "V22": 0.0, 81 | "V23": 1.0, 82 | "V24": 1.0, 83 | "V25": 1.0, 84 | "V26": 1.0, 85 | "V27": 0.0, 86 | "V28": 0.0, 87 | "V29": 0.0, 88 | "V30": 0.0, 89 | "V31": 0.0, 90 | "V32": 0.0, 91 | "V33": 0.0, 92 | "V34": 0.0, 93 | "V35": None, 94 | "V36": None, 95 | "V37": None, 96 | "V38": None, 97 | "V39": None, 98 | "V40": None, 99 | "V41": None, 100 | "V42": None, 101 | "V43": None, 102 | "V44": None, 103 | "V45": None, 104 | "V46": None, 105 | "V47": None, 106 | "V48": None, 107 | "V49": None, 108 | "V50": None, 109 | "V51": None, 110 | "V52": None, 111 | "V53": 1.0, 112 | "V54": 1.0, 113 | "V55": 1.0, 114 | "V56": 1.0, 115 | "V57": 0.0, 116 | "V58": 0.0, 117 | "V59": 0.0, 118 | "V60": 0.0, 119 | "V61": 1.0, 120 | "V62": 1.0, 121 | "V63": 0.0, 122 | "V64": 0.0, 123 | "V65": 1.0, 124 | "V66": 1.0, 125 | "V67": 1.0, 126 | "V68": 0.0, 127 | "V69": 0.0, 128 | "V70": 0.0, 129 | "V71": 0.0, 130 | "V72": 0.0, 131 | "V73": 0.0, 132 | "V74": 0.0, 133 | "V75": 1.0, 134 | "V76": 1.0, 135 | "V77": 1.0, 136 | "V78": 1.0, 137 | "V79": 0.0, 138 | "V80": 0.0, 139 | "V81": 0.0, 140 | "V82": 0.0, 141 | "V83": 0.0, 142 | "V84": 0.0, 143 | "V85": 0.0, 144 | "V86": 1.0, 145 | "V87": 1.0, 146 | "V88": 1.0, 147 | "V89": 0.0, 148 | "V90": 0.0, 149 | "V91": 0.0, 150 | "V92": 0.0, 151 | "V93": 0.0, 152 | "V94": 0.0, 153 | "V95": 0.0, 154 | "V96": 1.0, 155 | "V97": 0.0, 156 | "V98": 0.0, 157 | "V99": 0.0, 158 | "V100": 0.0, 159 | "V101": 0.0, 160 | "V102": 1.0, 161 | "V103": 0.0, 162 | "V104": 0.0, 163 | "V105": 0.0, 164 | "V106": 0.0, 165 | "V107": 1.0, 166 | "V108": 1.0, 167 | "V109": 1.0, 168 | "V110": 1.0, 169 | "V111": 1.0, 170 | "V112": 1.0, 171 | "V113": 1.0, 172 | "V114": 1.0, 173 | "V115": 1.0, 174 | "V116": 1.0, 175 | "V117": 1.0, 176 | "V118": 1.0, 177 | "V119": 1.0, 178 | "V120": 1.0, 179 | "V121": 1.0, 180 | "V122": 1.0, 181 | "V123": 1.0, 182 | "V124": 1.0, 183 | "V125": 1.0, 184 | "V126": 0.0, 185 | "V127": 117.0, 186 | "V128": 0.0, 187 | "V129": 0.0, 188 | "V130": 0.0, 189 | "V131": 0.0, 190 | "V132": 0.0, 191 | "V133": 117.0, 192 | "V134": 0.0, 193 | "V135": 0.0, 194 | "V136": 0.0, 195 | "V137": 0.0, 196 | "V138": None, 197 | "V139": None, 198 | "V140": None, 199 | "V141": None, 200 | "V142": None, 201 | "V143": None, 202 | "V144": None, 203 | "V145": None, 204 | "V146": None, 205 | "V147": None, 206 | "V148": None, 207 | "V149": None, 208 | "V150": None, 209 | "V151": None, 210 | "V152": None, 211 | "V153": None, 212 | "V154": None, 213 | "V155": None, 214 | "V156": None, 215 | "V157": None, 216 | "V158": None, 217 | "V159": None, 218 | "V160": None, 219 | "V161": None, 220 | "V162": None, 221 | "V163": None, 222 | "V164": None, 223 | "V165": None, 224 | "V166": None, 225 | "V167": None, 226 | "V168": None, 227 | "V169": None, 228 | "V170": None, 229 | "V171": None, 230 | "V172": None, 231 | "V173": None, 232 | "V174": None, 233 | "V175": None, 234 | "V176": None, 235 | "V177": None, 236 | "V178": None, 237 | "V179": None, 238 | "V180": None, 239 | "V181": None, 240 | "V182": None, 241 | "V183": None, 242 | "V184": None, 243 | "V185": None, 244 | "V186": None, 245 | "V187": None, 246 | "V188": None, 247 | "V189": None, 248 | "V190": None, 249 | "V191": None, 250 | "V192": None, 251 | "V193": None, 252 | "V194": None, 253 | "V195": None, 254 | "V196": None, 255 | "V197": None, 256 | "V198": None, 257 | "V199": None, 258 | "V200": None, 259 | "V201": None, 260 | "V202": None, 261 | "V203": None, 262 | "V204": None, 263 | "V205": None, 264 | "V206": None, 265 | "V207": None, 266 | "V208": None, 267 | "V209": None, 268 | "V210": None, 269 | "V211": None, 270 | "V212": None, 271 | "V213": None, 272 | "V214": None, 273 | "V215": None, 274 | "V216": None, 275 | "V217": None, 276 | "V218": None, 277 | "V219": None, 278 | "V220": None, 279 | "V221": None, 280 | "V222": None, 281 | "V223": None, 282 | "V224": None, 283 | "V225": None, 284 | "V226": None, 285 | "V227": None, 286 | "V228": None, 287 | "V229": None, 288 | "V230": None, 289 | "V231": None, 290 | "V232": None, 291 | "V233": None, 292 | "V234": None, 293 | "V235": None, 294 | "V236": None, 295 | "V237": None, 296 | "V238": None, 297 | "V239": None, 298 | "V240": None, 299 | "V241": None, 300 | "V242": None, 301 | "V243": None, 302 | "V244": None, 303 | "V245": None, 304 | "V246": None, 305 | "V247": None, 306 | "V248": None, 307 | "V249": None, 308 | "V250": None, 309 | "V251": None, 310 | "V252": None, 311 | "V253": None, 312 | "V254": None, 313 | "V255": None, 314 | "V256": None, 315 | "V257": None, 316 | "V258": None, 317 | "V259": None, 318 | "V260": None, 319 | "V261": None, 320 | "V262": None, 321 | "V263": None, 322 | "V264": None, 323 | "V265": None, 324 | "V266": None, 325 | "V267": None, 326 | "V268": None, 327 | "V269": None, 328 | "V270": None, 329 | "V271": None, 330 | "V272": None, 331 | "V273": None, 332 | "V274": None, 333 | "V275": None, 334 | "V276": None, 335 | "V277": None, 336 | "V278": None, 337 | "V279": 0.0, 338 | "V280": 0.0, 339 | "V281": 0.0, 340 | "V282": 1.0, 341 | "V283": 1.0, 342 | "V284": 0.0, 343 | "V285": 0.0, 344 | "V286": 0.0, 345 | "V287": 0.0, 346 | "V288": 0.0, 347 | "V289": 0.0, 348 | "V290": 1.0, 349 | "V291": 1.0, 350 | "V292": 1.0, 351 | "V293": 0.0, 352 | "V294": 1.0, 353 | "V295": 0.0, 354 | "V296": 0.0, 355 | "V297": 0.0, 356 | "V298": 0.0, 357 | "V299": 0.0, 358 | "V300": 0.0, 359 | "V301": 0.0, 360 | "V302": 0.0, 361 | "V303": 0.0, 362 | "V304": 0.0, 363 | "V305": 1.0, 364 | "V306": 0.0, 365 | "V307": 117.0, 366 | "V308": 0.0, 367 | "V309": 0.0, 368 | "V310": 0.0, 369 | "V311": 0.0, 370 | "V312": 0.0, 371 | "V313": 0.0, 372 | "V314": 0.0, 373 | "V315": 0.0, 374 | "V316": 0.0, 375 | "V317": 117.0, 376 | "V318": 0.0, 377 | "V319": 0.0, 378 | "V320": 0.0, 379 | "V321": 0.0, 380 | "V322": None, 381 | "V323": None, 382 | "V324": None, 383 | "V325": None, 384 | "V326": None, 385 | "V327": None, 386 | "V328": None, 387 | "V329": None, 388 | "V330": None, 389 | "V331": None, 390 | "V332": None, 391 | "V333": None, 392 | "V334": None, 393 | "V335": None, 394 | "V336": None, 395 | "V337": None, 396 | "V338": None, 397 | "V339": None, 398 | } 399 | ] 400 | 401 | sample_input = pd.DataFrame(sample_json) 402 | -------------------------------------------------------------------------------- /inference_graph_demo/sample.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | 3 | sample_json = [ 4 | { 5 | "TransactionID": 2987000, 6 | "TransactionDT": 86400, 7 | "TransactionAmt": 68.5, 8 | "ProductCD": "W", 9 | "card1": 13926, 10 | "card2": None, 11 | "card3": 150.0, 12 | "card4": "discover", 13 | "card5": 142.0, 14 | "card6": "credit", 15 | "addr1": 315.0, 16 | "addr2": 87.0, 17 | "dist1": 19.0, 18 | "dist2": None, 19 | "P_emaildomain": None, 20 | "R_emaildomain": None, 21 | "C1": 1.0, 22 | "C2": 1.0, 23 | "C3": 0.0, 24 | "C4": 0.0, 25 | "C5": 0.0, 26 | "C6": 1.0, 27 | "C7": 0.0, 28 | "C8": 0.0, 29 | "C9": 1.0, 30 | "C10": 0.0, 31 | "C11": 2.0, 32 | "C12": 0.0, 33 | "C13": 1.0, 34 | "C14": 1.0, 35 | "D1": 14.0, 36 | "D2": None, 37 | "D3": 13.0, 38 | "D4": None, 39 | "D5": None, 40 | "D6": None, 41 | "D7": None, 42 | "D8": None, 43 | "D9": None, 44 | "D10": 13.0, 45 | "D11": 13.0, 46 | "D12": None, 47 | "D13": None, 48 | "D14": None, 49 | "D15": 0.0, 50 | "M1": "T", 51 | "M2": "T", 52 | "M3": "T", 53 | "M4": "M2", 54 | "M5": "F", 55 | "M6": "T", 56 | "M7": None, 57 | "M8": None, 58 | "M9": None, 59 | "V1": 1.0, 60 | "V2": 1.0, 61 | "V3": 1.0, 62 | "V4": 1.0, 63 | "V5": 1.0, 64 | "V6": 1.0, 65 | "V7": 1.0, 66 | "V8": 1.0, 67 | "V9": 1.0, 68 | "V10": 0.0, 69 | "V11": 0.0, 70 | "V12": 1.0, 71 | "V13": 1.0, 72 | "V14": 1.0, 73 | "V15": 0.0, 74 | "V16": 0.0, 75 | "V17": 0.0, 76 | "V18": 0.0, 77 | "V19": 1.0, 78 | "V20": 1.0, 79 | "V21": 0.0, 80 | "V22": 0.0, 81 | "V23": 1.0, 82 | "V24": 1.0, 83 | "V25": 1.0, 84 | "V26": 1.0, 85 | "V27": 0.0, 86 | "V28": 0.0, 87 | "V29": 0.0, 88 | "V30": 0.0, 89 | "V31": 0.0, 90 | "V32": 0.0, 91 | "V33": 0.0, 92 | "V34": 0.0, 93 | "V35": None, 94 | "V36": None, 95 | "V37": None, 96 | "V38": None, 97 | "V39": None, 98 | "V40": None, 99 | "V41": None, 100 | "V42": None, 101 | "V43": None, 102 | "V44": None, 103 | "V45": None, 104 | "V46": None, 105 | "V47": None, 106 | "V48": None, 107 | "V49": None, 108 | "V50": None, 109 | "V51": None, 110 | "V52": None, 111 | "V53": 1.0, 112 | "V54": 1.0, 113 | "V55": 1.0, 114 | "V56": 1.0, 115 | "V57": 0.0, 116 | "V58": 0.0, 117 | "V59": 0.0, 118 | "V60": 0.0, 119 | "V61": 1.0, 120 | "V62": 1.0, 121 | "V63": 0.0, 122 | "V64": 0.0, 123 | "V65": 1.0, 124 | "V66": 1.0, 125 | "V67": 1.0, 126 | "V68": 0.0, 127 | "V69": 0.0, 128 | "V70": 0.0, 129 | "V71": 0.0, 130 | "V72": 0.0, 131 | "V73": 0.0, 132 | "V74": 0.0, 133 | "V75": 1.0, 134 | "V76": 1.0, 135 | "V77": 1.0, 136 | "V78": 1.0, 137 | "V79": 0.0, 138 | "V80": 0.0, 139 | "V81": 0.0, 140 | "V82": 0.0, 141 | "V83": 0.0, 142 | "V84": 0.0, 143 | "V85": 0.0, 144 | "V86": 1.0, 145 | "V87": 1.0, 146 | "V88": 1.0, 147 | "V89": 0.0, 148 | "V90": 0.0, 149 | "V91": 0.0, 150 | "V92": 0.0, 151 | "V93": 0.0, 152 | "V94": 0.0, 153 | "V95": 0.0, 154 | "V96": 1.0, 155 | "V97": 0.0, 156 | "V98": 0.0, 157 | "V99": 0.0, 158 | "V100": 0.0, 159 | "V101": 0.0, 160 | "V102": 1.0, 161 | "V103": 0.0, 162 | "V104": 0.0, 163 | "V105": 0.0, 164 | "V106": 0.0, 165 | "V107": 1.0, 166 | "V108": 1.0, 167 | "V109": 1.0, 168 | "V110": 1.0, 169 | "V111": 1.0, 170 | "V112": 1.0, 171 | "V113": 1.0, 172 | "V114": 1.0, 173 | "V115": 1.0, 174 | "V116": 1.0, 175 | "V117": 1.0, 176 | "V118": 1.0, 177 | "V119": 1.0, 178 | "V120": 1.0, 179 | "V121": 1.0, 180 | "V122": 1.0, 181 | "V123": 1.0, 182 | "V124": 1.0, 183 | "V125": 1.0, 184 | "V126": 0.0, 185 | "V127": 117.0, 186 | "V128": 0.0, 187 | "V129": 0.0, 188 | "V130": 0.0, 189 | "V131": 0.0, 190 | "V132": 0.0, 191 | "V133": 117.0, 192 | "V134": 0.0, 193 | "V135": 0.0, 194 | "V136": 0.0, 195 | "V137": 0.0, 196 | "V138": None, 197 | "V139": None, 198 | "V140": None, 199 | "V141": None, 200 | "V142": None, 201 | "V143": None, 202 | "V144": None, 203 | "V145": None, 204 | "V146": None, 205 | "V147": None, 206 | "V148": None, 207 | "V149": None, 208 | "V150": None, 209 | "V151": None, 210 | "V152": None, 211 | "V153": None, 212 | "V154": None, 213 | "V155": None, 214 | "V156": None, 215 | "V157": None, 216 | "V158": None, 217 | "V159": None, 218 | "V160": None, 219 | "V161": None, 220 | "V162": None, 221 | "V163": None, 222 | "V164": None, 223 | "V165": None, 224 | "V166": None, 225 | "V167": None, 226 | "V168": None, 227 | "V169": None, 228 | "V170": None, 229 | "V171": None, 230 | "V172": None, 231 | "V173": None, 232 | "V174": None, 233 | "V175": None, 234 | "V176": None, 235 | "V177": None, 236 | "V178": None, 237 | "V179": None, 238 | "V180": None, 239 | "V181": None, 240 | "V182": None, 241 | "V183": None, 242 | "V184": None, 243 | "V185": None, 244 | "V186": None, 245 | "V187": None, 246 | "V188": None, 247 | "V189": None, 248 | "V190": None, 249 | "V191": None, 250 | "V192": None, 251 | "V193": None, 252 | "V194": None, 253 | "V195": None, 254 | "V196": None, 255 | "V197": None, 256 | "V198": None, 257 | "V199": None, 258 | "V200": None, 259 | "V201": None, 260 | "V202": None, 261 | "V203": None, 262 | "V204": None, 263 | "V205": None, 264 | "V206": None, 265 | "V207": None, 266 | "V208": None, 267 | "V209": None, 268 | "V210": None, 269 | "V211": None, 270 | "V212": None, 271 | "V213": None, 272 | "V214": None, 273 | "V215": None, 274 | "V216": None, 275 | "V217": None, 276 | "V218": None, 277 | "V219": None, 278 | "V220": None, 279 | "V221": None, 280 | "V222": None, 281 | "V223": None, 282 | "V224": None, 283 | "V225": None, 284 | "V226": None, 285 | "V227": None, 286 | "V228": None, 287 | "V229": None, 288 | "V230": None, 289 | "V231": None, 290 | "V232": None, 291 | "V233": None, 292 | "V234": None, 293 | "V235": None, 294 | "V236": None, 295 | "V237": None, 296 | "V238": None, 297 | "V239": None, 298 | "V240": None, 299 | "V241": None, 300 | "V242": None, 301 | "V243": None, 302 | "V244": None, 303 | "V245": None, 304 | "V246": None, 305 | "V247": None, 306 | "V248": None, 307 | "V249": None, 308 | "V250": None, 309 | "V251": None, 310 | "V252": None, 311 | "V253": None, 312 | "V254": None, 313 | "V255": None, 314 | "V256": None, 315 | "V257": None, 316 | "V258": None, 317 | "V259": None, 318 | "V260": None, 319 | "V261": None, 320 | "V262": None, 321 | "V263": None, 322 | "V264": None, 323 | "V265": None, 324 | "V266": None, 325 | "V267": None, 326 | "V268": None, 327 | "V269": None, 328 | "V270": None, 329 | "V271": None, 330 | "V272": None, 331 | "V273": None, 332 | "V274": None, 333 | "V275": None, 334 | "V276": None, 335 | "V277": None, 336 | "V278": None, 337 | "V279": 0.0, 338 | "V280": 0.0, 339 | "V281": 0.0, 340 | "V282": 1.0, 341 | "V283": 1.0, 342 | "V284": 0.0, 343 | "V285": 0.0, 344 | "V286": 0.0, 345 | "V287": 0.0, 346 | "V288": 0.0, 347 | "V289": 0.0, 348 | "V290": 1.0, 349 | "V291": 1.0, 350 | "V292": 1.0, 351 | "V293": 0.0, 352 | "V294": 1.0, 353 | "V295": 0.0, 354 | "V296": 0.0, 355 | "V297": 0.0, 356 | "V298": 0.0, 357 | "V299": 0.0, 358 | "V300": 0.0, 359 | "V301": 0.0, 360 | "V302": 0.0, 361 | "V303": 0.0, 362 | "V304": 0.0, 363 | "V305": 1.0, 364 | "V306": 0.0, 365 | "V307": 117.0, 366 | "V308": 0.0, 367 | "V309": 0.0, 368 | "V310": 0.0, 369 | "V311": 0.0, 370 | "V312": 0.0, 371 | "V313": 0.0, 372 | "V314": 0.0, 373 | "V315": 0.0, 374 | "V316": 0.0, 375 | "V317": 117.0, 376 | "V318": 0.0, 377 | "V319": 0.0, 378 | "V320": 0.0, 379 | "V321": 0.0, 380 | "V322": None, 381 | "V323": None, 382 | "V324": None, 383 | "V325": None, 384 | "V326": None, 385 | "V327": None, 386 | "V328": None, 387 | "V329": None, 388 | "V330": None, 389 | "V331": None, 390 | "V332": None, 391 | "V333": None, 392 | "V334": None, 393 | "V335": None, 394 | "V336": None, 395 | "V337": None, 396 | "V338": None, 397 | "V339": None, 398 | } 399 | ] 400 | 401 | sample_input = pd.DataFrame(sample_json) 402 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------