From 94c218ff1dd67519972c881bc55f5534550cccff Mon Sep 17 00:00:00 2001 From: androiddrew Date: Thu, 24 Mar 2022 13:54:01 -0400 Subject: [PATCH] Saving sklearn example --- .gitignore | 1 + dev-requirements.in | 3 ++ dev-requirements.txt | 40 ++++++++++++++++++++++ mnist_ex/get_model.sh | 0 requirements.in | 7 ++++ requirements.txt | 55 ++++++++++++++++++++++++++++++ scikit_learn_ex/output/.gitignore | 2 ++ scikit_learn_ex/train.py | 22 ++++++++++++ sklearn_ex/README.md | 27 +++++++++++++++ sklearn_ex/convert_to_onnx.py | 48 ++++++++++++++++++++++++++ sklearn_ex/img/model_graph.png | Bin 0 -> 28020 bytes sklearn_ex/onnx_infer.py | 0 sklearn_ex/output/.gitignore | 2 ++ sklearn_ex/train.py | 24 +++++++++++++ 14 files changed, 231 insertions(+) create mode 100644 dev-requirements.in create mode 100644 dev-requirements.txt create mode 100644 mnist_ex/get_model.sh create mode 100644 requirements.in create mode 100644 requirements.txt create mode 100644 scikit_learn_ex/output/.gitignore create mode 100644 scikit_learn_ex/train.py create mode 100644 sklearn_ex/README.md create mode 100644 sklearn_ex/convert_to_onnx.py create mode 100644 sklearn_ex/img/model_graph.png create mode 100644 sklearn_ex/onnx_infer.py create mode 100644 sklearn_ex/output/.gitignore create mode 100644 sklearn_ex/train.py diff --git a/.gitignore b/.gitignore index f8b73e7..0c5c3fa 100644 --- a/.gitignore +++ b/.gitignore @@ -138,3 +138,4 @@ dmypy.json # Cython debug symbols cython_debug/ +./*/output \ No newline at end of file diff --git a/dev-requirements.in b/dev-requirements.in new file mode 100644 index 0000000..bd7c5d2 --- /dev/null +++ b/dev-requirements.in @@ -0,0 +1,3 @@ +black +flake8 +pip-tools diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..1102ead --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,40 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile dev-requirements.in +# +black==22.1.0 + # via -r dev-requirements.in +click==8.0.4 + # via + # black + # pip-tools +flake8==4.0.1 + # via -r dev-requirements.in +mccabe==0.6.1 + # via flake8 +mypy-extensions==0.4.3 + # via black +pathspec==0.9.0 + # via black +pep517==0.12.0 + # via pip-tools +pip-tools==6.5.1 + # via -r dev-requirements.in +platformdirs==2.5.1 + # via black +pycodestyle==2.8.0 + # via flake8 +pyflakes==2.4.0 + # via flake8 +tomli==2.0.1 + # via black +typing-extensions==4.1.1 + # via black +wheel==0.37.1 + # via pip-tools + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/mnist_ex/get_model.sh b/mnist_ex/get_model.sh new file mode 100644 index 0000000..e69de29 diff --git a/requirements.in b/requirements.in new file mode 100644 index 0000000..3b978ab --- /dev/null +++ b/requirements.in @@ -0,0 +1,7 @@ +joblib +numpy +onnx +onnxruntime +opencv-python +skl2onnx +sklearn \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f9b94e0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,55 @@ +# +# This file is autogenerated by pip-compile with python 3.8 +# To update, run: +# +# pip-compile requirements.in +# +flatbuffers==2.0 + # via onnxruntime +joblib==1.1.0 + # via + # -r requirements.in + # scikit-learn +numpy==1.22.3 + # via + # -r requirements.in + # onnx + # onnxconverter-common + # onnxruntime + # opencv-python + # scikit-learn + # scipy + # skl2onnx +onnx==1.11.0 + # via + # -r requirements.in + # onnxconverter-common + # skl2onnx +onnxconverter-common==1.9.0 + # via skl2onnx +onnxruntime==1.10.0 + # via -r requirements.in +opencv-python==4.5.5.64 + # via -r requirements.in +protobuf==3.19.4 + # via + # onnx + # onnxconverter-common + # onnxruntime + # skl2onnx +scikit-learn==1.0.2 + # via + # skl2onnx + # sklearn +scipy==1.8.0 + # via + # scikit-learn + # skl2onnx +skl2onnx==1.11 + # via -r requirements.in +sklearn==0.0 + # via -r requirements.in +threadpoolctl==3.1.0 + # via scikit-learn +typing-extensions==4.1.1 + # via onnx diff --git a/scikit_learn_ex/output/.gitignore b/scikit_learn_ex/output/.gitignore new file mode 100644 index 0000000..53ce133 --- /dev/null +++ b/scikit_learn_ex/output/.gitignore @@ -0,0 +1,2 @@ +*.pkl +*.onnx \ No newline at end of file diff --git a/scikit_learn_ex/train.py b/scikit_learn_ex/train.py new file mode 100644 index 0000000..224907c --- /dev/null +++ b/scikit_learn_ex/train.py @@ -0,0 +1,22 @@ +from turtle import pd +import joblib as jl + +from sklearn.datasets import load_iris +from sklearn.model_selection import train_test_split +from sklearn.ensemble import RandomForestClassifier + +def main(): + # Use iris dataset + iris = load_iris() + X, y = iris.data, iris.target + X_train, X_test, y_train, y_test = train_test_split(X, y) + clr = RandomForestClassifier() + # Fit + clr.fit(X_train, y_train) + # Serialize the classifier to pickle file + jl.dump(clr, "./output/model.pkl", compress=9) + +if __name__ == "__main__": + print("Building iris model...") + main() + print("Model trained and dumped as pickle file.") \ No newline at end of file diff --git a/sklearn_ex/README.md b/sklearn_ex/README.md new file mode 100644 index 0000000..6b8d0e5 --- /dev/null +++ b/sklearn_ex/README.md @@ -0,0 +1,27 @@ +# sklearn example + +This is a simple demo showing the training of Randmon Forest Classifier, serializing it as a pickle file, converting it to an Onnx model, then making inferences using the Onnx model. + +## Usage + +Train the model + +``` +python train.py +``` + +Convert to Onnx + +``` + +``` + +Make inferences + +``` + +``` + +## Model + +![Model Graph](./img/model_graph.png) \ No newline at end of file diff --git a/sklearn_ex/convert_to_onnx.py b/sklearn_ex/convert_to_onnx.py new file mode 100644 index 0000000..de9509d --- /dev/null +++ b/sklearn_ex/convert_to_onnx.py @@ -0,0 +1,48 @@ +import argparse +import pathlib + +import joblib as jl + +from skl2onnx import convert_sklearn +from skl2onnx.common.data_types import FloatTensorType + + +def convert_model_to_onnx(path): + """Converts the example sklearn classifier to Onnx""" + clr_model = jl.load(path) + # Define Initial Types + initial_type = [("float_input", FloatTensorType([None, 4]))] + onnx_model = convert_sklearn(clr_model, initial_types=initial_type) + return onnx_model + + +def write_onnx_file(model, output_path): + """Writes an Onnx model to a desired file location""" + with open(output_path, mode="wb") as f: + f.write(model.SerializeToString()) + + +def main(args): + print(f"Converting {args.model_path} to Onnx") + model = convert_model_to_onnx(args.model_path) + print(f"Writing saving Onnx file to {args.output_path}") + write_onnx_file(model, args.output_path) + print("Done") + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Converts a pickled classifier to onnx format" + ) + parser.add_argument( + "model_path", type=pathlib.Path, help="Path to classifier pickle file" + ) + parser.add_argument( + "-o" "--out", + type=pathlib.Path, + dest="output_path", + default=pathlib.Path("./output/clr_model.onnx"), + help="Path to output Onnx file", + ) + args = parser.parse_args() + main(args) diff --git a/sklearn_ex/img/model_graph.png b/sklearn_ex/img/model_graph.png new file mode 100644 index 0000000000000000000000000000000000000000..76af5e935893ef229b641297fad1f206bced60b3 GIT binary patch literal 28020 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 literal 0 HcmV?d00001 diff --git a/sklearn_ex/onnx_infer.py b/sklearn_ex/onnx_infer.py new file mode 100644 index 0000000..e69de29 diff --git a/sklearn_ex/output/.gitignore b/sklearn_ex/output/.gitignore new file mode 100644 index 0000000..53ce133 --- /dev/null +++ b/sklearn_ex/output/.gitignore @@ -0,0 +1,2 @@ +*.pkl +*.onnx \ No newline at end of file diff --git a/sklearn_ex/train.py b/sklearn_ex/train.py new file mode 100644 index 0000000..0768048 --- /dev/null +++ b/sklearn_ex/train.py @@ -0,0 +1,24 @@ +from turtle import pd +import joblib as jl + +from sklearn.datasets import load_iris +from sklearn.model_selection import train_test_split +from sklearn.ensemble import RandomForestClassifier + + +def main(): + # Use iris dataset + iris = load_iris() + X, y = iris.data, iris.target + X_train, X_test, y_train, y_test = train_test_split(X, y) + clr = RandomForestClassifier() + # Fit + clr.fit(X_train, y_train) + # Serialize the classifier to pickle file + jl.dump(clr, "./output/model.pkl", compress=9) + + +if __name__ == "__main__": + print("Building iris model...") + main() + print("Model trained and dumped as pickle file.")