From ca5b7ee0e787c80bad03e40c31c260cf4ecd6e50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Antonio=20Perdiguero=20L=C3=B3pez?= Date: Thu, 9 Jun 2022 19:55:27 +0200 Subject: [PATCH] :sparkles: Model resources --- flama/applications.py | 6 +- flama/models/components.py | 21 ++- flama/models/modules.py | 28 +-- flama/models/resource.py | 109 ++++++++++++ flama/resources/rest.py | 7 +- flama/routing.py | 3 + flama/schemas/_libs/marshmallow/schemas.py | 18 ++ flama/schemas/_libs/typesystem/schemas.py | 10 ++ tests/models/conftest.py | 48 ++++++ tests/models/sklearn_model.flm | Bin 0 -> 829 bytes tests/models/tensorflow_model.flm | Bin 0 -> 70114 bytes tests/models/test_components.py | 62 ++----- tests/models/test_resource.py | 192 +++++++++++++++++++++ tests/resources/test_resource.py | 2 +- 14 files changed, 430 insertions(+), 76 deletions(-) create mode 100644 flama/models/resource.py create mode 100644 tests/models/conftest.py create mode 100644 tests/models/sklearn_model.flm create mode 100644 tests/models/tensorflow_model.flm create mode 100644 tests/models/test_resource.py diff --git a/flama/applications.py b/flama/applications.py index 8fbf95ea..a40ab98f 100644 --- a/flama/applications.py +++ b/flama/applications.py @@ -8,6 +8,7 @@ from flama.exceptions import HTTPException from flama.injection import Injector from flama.lifespan import Lifespan +from flama.models.modules import ModelsModule from flama.modules import Modules from flama.pagination import paginator from flama.resources import ResourcesModule @@ -28,7 +29,7 @@ __all__ = ["Flama"] -DEFAULT_MODULES: typing.List[typing.Type["Module"]] = [SQLAlchemyModule, ResourcesModule, SchemaModule] +DEFAULT_MODULES: typing.List[typing.Type["Module"]] = [SQLAlchemyModule, ResourcesModule, SchemaModule, ModelsModule] class Flama(Starlette): @@ -106,6 +107,9 @@ def injector(self) -> Injector: def components(self) -> "Components": return self.router.components + def add_component(self, component: "Component"): + self.router.add_component(component) + @property def routes(self) -> typing.List["BaseRoute"]: # type: ignore[override] return self.router.routes diff --git a/flama/models/components.py b/flama/models/components.py index bfa5e31f..df0b8aa2 100644 --- a/flama/models/components.py +++ b/flama/models/components.py @@ -1,4 +1,5 @@ import abc +import json import typing from flama.components import Component @@ -11,19 +12,29 @@ class Model: def __init__(self, model: typing.Any): self.model = model + @abc.abstractmethod + def inspect(self) -> typing.Any: + ... + @abc.abstractmethod def predict(self, x: typing.Any) -> typing.Any: ... class TensorFlowModel(Model): - def predict(self, x: typing.Any) -> typing.Any: - return self.model.predict(x) + def inspect(self) -> typing.Any: + return json.loads(self.model.to_json()) + + def predict(self, x: typing.List[typing.List[typing.Any]]) -> typing.Any: + return self.model.predict(x).tolist() class SKLearnModel(Model): - def predict(self, x: typing.Any) -> typing.Any: - return self.model.predict(x) + def inspect(self) -> typing.Any: + return self.model.get_params() + + def predict(self, x: typing.List[typing.List[typing.Any]]) -> typing.Any: + return self.model.predict(x).tolist() class ModelComponentBuilder: @@ -39,7 +50,7 @@ class ModelComponent(Component): def __init__(self, model: model_class): # type: ignore[valid-type] self.model = model - def resolve(self, test: bool) -> model_class: # type: ignore[valid-type] + def resolve(self) -> model_class: # type: ignore[valid-type] return self.model return ModelComponent(model_obj) diff --git a/flama/models/modules.py b/flama/models/modules.py index 7668febf..5c18a245 100644 --- a/flama/models/modules.py +++ b/flama/models/modules.py @@ -1,30 +1,32 @@ -import inspect +import os import typing +from flama.models.resource import ModelResource, ModelResourceType from flama.modules import Module -from flama.resources.routing import ResourceRoute - -if typing.TYPE_CHECKING: - from flama.resources.resource import BaseResource __all__ = ["ModelsModule"] class ModelsModule(Module): - name = "resources" + name = "models" - def add_model( - self, path: str, resource: typing.Union["BaseResource", typing.Type["BaseResource"]], *args, **kwargs - ): + def add_model(self, path: str, model: typing.Union[str, os.PathLike], name: str, *args, **kwargs): """Adds a model to this application, setting its endpoints. :param path: Resource base path. - :param resource: Resource class. + :param model: Model path. + :param name: Model name. """ - # Handle class or instance objects - resource = resource(app=self.app, *args, **kwargs) if inspect.isclass(resource) else resource + name_ = name + model_ = model + + class Resource(ModelResource, metaclass=ModelResourceType): + name = name_ + model = model_ - self.app.routes.append(ResourceRoute(path, resource, main_app=self.app)) + resource = Resource() + self.app.resources.add_resource(path, resource) # type: ignore[attr-defined] + self.app.add_component(resource.component) # type: ignore def model(self, path: str, *args, **kwargs) -> typing.Callable: """Decorator for Model classes for adding them to the application. diff --git a/flama/models/resource.py b/flama/models/resource.py new file mode 100644 index 00000000..779fddf9 --- /dev/null +++ b/flama/models/resource.py @@ -0,0 +1,109 @@ +import os +import typing + +import flama.schemas +from flama.models.components import ModelComponentBuilder +from flama.resources import types, BaseResource +from flama.resources.exceptions import ResourceAttributeError +from flama.resources.resource import ResourceType +from flama.resources.routing import resource_method +import flama.schemas + +if typing.TYPE_CHECKING: + from flama.components import Component + from flama.models.components import Model + +__all__ = ["ModelResource", "InspectMixin", "PredictMixin", "ModelResourceType"] + + +class InspectMixin: + @classmethod + def _add_inspect( + mcs, name: str, verbose_name: str, ml_model_type: "Model", **kwargs + ) -> typing.Dict[str, typing.Any]: + @resource_method("/", methods=["GET"], name=f"{name}-inspect") + async def inspect(self, model: ml_model_type): # type: ignore[valid-type] + return model.inspect() # type: ignore[attr-defined] + + inspect.__doc__ = f""" + tags: + - {verbose_name} + summary: + Retrieve the model. + description: + Retrieve the model from this resource. + responses: + 200: + description: + The model. + """ + + return {"_inspect": inspect} + + +class PredictMixin: + @classmethod + def _add_predict( + mcs, name: str, verbose_name: str, ml_model_type: "Model", **kwargs + ) -> typing.Dict[str, typing.Any]: + @resource_method("/predict/", methods=["POST"], name=f"{name}-predict") + async def predict( + self, model: ml_model_type, data: flama.schemas.schemas.MLModelInput # type: ignore[valid-type] + ) -> flama.schemas.schemas.MLModelOutput: + return {"output": model.predict(data["input"])} # type: ignore[attr-defined] + + predict.__doc__ = f""" + tags: + - {verbose_name} + summary: + Generate a prediction. + description: + Generate a prediction using the model from this resource. + responses: + 200: + description: + The prediction generated by the model. + """ + + return {"_predict": predict} + + +class ModelResource(BaseResource): + model: typing.Union[str, os.PathLike] + + +class ModelResourceType(ResourceType, InspectMixin, PredictMixin): + METHODS = ("inspect", "predict") + + def __new__(mcs, name: str, bases: typing.Tuple[type], namespace: typing.Dict[str, typing.Any]): + """Resource metaclass for defining basic behavior for ML resources: + * Create _meta attribute containing some metadata (model...). + * Adds methods related to ML resource (inspect, predict...) listed in METHODS class attribute. + + :param name: Class name. + :param bases: List of superclasses. + :param namespace: Variables namespace used to create the class. + """ + try: + # Get model component + component = mcs._get_model_component(bases, namespace) + model = component.model # type: ignore[attr-defined] + namespace["component"] = component + namespace["model"] = component.model # type: ignore[attr-defined] + except AttributeError as e: + raise ResourceAttributeError(str(e), name) + + metadata_namespace = {"component": component, "model": model, "model_type": type(model)} + if "_meta" in namespace: + namespace["_meta"].namespaces["ml"] = metadata_namespace + else: + namespace["_meta"] = types.Metadata(namespaces={"ml": metadata_namespace}) + + return super().__new__(mcs, name, bases, namespace) + + @classmethod + def _get_model_component( + mcs, bases: typing.Sequence[typing.Any], namespace: typing.Dict[str, typing.Any] + ) -> "Component": + with open(mcs._get_attribute("model", bases, namespace), "rb") as f: + return ModelComponentBuilder.loads(f.read()) diff --git a/flama/resources/rest.py b/flama/resources/rest.py index f3b8d028..e166266f 100644 --- a/flama/resources/rest.py +++ b/flama/resources/rest.py @@ -33,17 +33,16 @@ class RESTResource(BaseResource): class RESTResourceType(ResourceType): def __new__(mcs, name: str, bases: typing.Tuple[type], namespace: typing.Dict[str, typing.Any]): - """Resource metaclass for defining basic behavior: - * Create _meta attribute containing some metadata (model, schemas, names...). + """Resource metaclass for defining basic behavior for REST resources: + * Create _meta attribute containing some metadata (model, schemas...). * Adds methods related to REST resource (create, retrieve, update, delete...) listed in METHODS class attribute. - * Generate a Router with above methods. :param name: Class name. :param bases: List of superclasses. :param namespace: Variables namespace used to create the class. """ try: - # Get model and replace it with a read-only descriptor + # Get model model = mcs._get_model(bases, namespace) namespace["model"] = model.table diff --git a/flama/routing.py b/flama/routing.py index 63173fbf..dc5baead 100644 --- a/flama/routing.py +++ b/flama/routing.py @@ -263,6 +263,9 @@ def components(self) -> Components: ] ) + def add_component(self, component: Component): + self._components.append(component) + def mount(self, path: str, app: ASGIApp, name: str = None) -> None: try: main_app = self.main_app diff --git a/flama/schemas/_libs/marshmallow/schemas.py b/flama/schemas/_libs/marshmallow/schemas.py index 09e94146..d5dc4588 100644 --- a/flama/schemas/_libs/marshmallow/schemas.py +++ b/flama/schemas/_libs/marshmallow/schemas.py @@ -51,6 +51,22 @@ class PageNumber(marshmallow.Schema): data = marshmallow.fields.List(marshmallow.fields.Dict(), required=True) +class MLModelInput(marshmallow.Schema): + input = marshmallow.fields.List( + marshmallow.fields.Raw(), + required=True, + metadata={"title": "input", "description": "Model input"}, + ) + + +class MLModelOutput(marshmallow.Schema): + output = marshmallow.fields.List( + marshmallow.fields.Raw(), + required=True, + metadata={"title": "output", "description": "Model output"}, + ) + + SCHEMAS = { "APIError": APIError, "DropCollection": DropCollection, @@ -58,4 +74,6 @@ class PageNumber(marshmallow.Schema): "LimitOffset": LimitOffset, "PageNumberMeta": PageNumberMeta, "PageNumber": PageNumber, + "MLModelInput": MLModelInput, + "MLModelOutput": MLModelOutput, } diff --git a/flama/schemas/_libs/typesystem/schemas.py b/flama/schemas/_libs/typesystem/schemas.py index c81c3262..0c9d2f8a 100644 --- a/flama/schemas/_libs/typesystem/schemas.py +++ b/flama/schemas/_libs/typesystem/schemas.py @@ -69,3 +69,13 @@ } ) SCHEMAS["PageNumber"] = PageNumber + +MLModelInput = typesystem.Schema( + fields={"input": typesystem.fields.Array(typesystem.fields.Any(), title="input", description="Model input")} +) +SCHEMAS["MLModelInput"] = MLModelInput + +MLModelOutput = typesystem.Schema( + fields={"output": typesystem.fields.Array(typesystem.fields.Any(), title="input", description="Model input")} +) +SCHEMAS["MLModelOutput"] = MLModelOutput diff --git a/tests/models/conftest.py b/tests/models/conftest.py new file mode 100644 index 00000000..ed3ea9a3 --- /dev/null +++ b/tests/models/conftest.py @@ -0,0 +1,48 @@ +import pytest +import tensorflow as tf +from sklearn.linear_model import LogisticRegression + +import flama + + +def tensorflow_model( + sequential=tf.keras.models.Sequential( + [ + tf.keras.layers.Flatten(input_shape=(28, 28)), + tf.keras.layers.Dense(128, activation="relu"), + tf.keras.layers.Dropout(0.2), + tf.keras.layers.Dense(10, activation="softmax"), + ] + ) +): + tf_model = sequential + + tf_model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]) + + return tf_model + + +def sklearn_model(): + return LogisticRegression() + + +@pytest.fixture(scope="function") +def model(request): + if request.param == "tensorflow": + return tensorflow_model() + + if request.param == "sklearn": + return sklearn_model() + + raise ValueError("Unknown model") + + +@pytest.fixture(scope="function") +def model_dump(request): + if request.param == "tensorflow": + return flama.dumps("tensorflow", tensorflow_model()) + + if request.param == "sklearn": + return flama.dumps("sklearn", sklearn_model()) + + raise ValueError("Unknown model") diff --git a/tests/models/sklearn_model.flm b/tests/models/sklearn_model.flm new file mode 100644 index 0000000000000000000000000000000000000000..2ccd1a4b771a0b4f17abe81324224e35c13354f9 GIT binary patch literal 829 zcmV-D1H$}xoK=+DlBzfqhF@iux9%zhrD~X}xd<3eDhdc86gLo>gNEp|2clE+?i0Z2 z-a8i%!eXs2|N6;46WZjHKYvWFC;E|nvdPaMllEME(0;7~?vcp1Yl4ht-YC}$DHO*} znIrX-pza>a{E^7?RhaaspT6f|8!^&GFCx=NUR^lQTPUi;{S3T^ zhF4ynA-NQWddZnjN$XN#`CPYa42O60UYOAn%TXs{UMa(}(eF+$(hZ2JZJ!6rye12` zEad2t$n~6fmmL~lv?oT&DVL>^Ec{wz;`&^{TE7R&eWWb65=t1{A`te`SKKCyETD^q zZE80h*JT#_eatS9eXRFMO-T}JTw>Y1;@Eu=PaTv<888j0FjWqX%Idj_R*<*qD~X{W zbQ;!&x3Y2AB)q%LJ2fpW|j4&AgPy>Q19$ES5H*08MJ1<$iU?p$Xu z#cvv`%`rn4$Pe zc{}E`B>vQC?1I~d!|kB%c?ScfY;VEla8h=`V)!f_P6_u?l{;+}XWB^Y$W_mJ7Oa<%)ig+OIa{>S`#jmf=j&x_i=koZgj3Wj5mP;ybi-)5V_pQEsl2Dux&GN65P5%84 HO1zBtE|aP^ literal 0 HcmV?d00001 diff --git a/tests/models/tensorflow_model.flm b/tests/models/tensorflow_model.flm new file mode 100644 index 0000000000000000000000000000000000000000..787300a9fc103a0d1cdd3b8159bf0a08ddea8bb0 GIT binary patch literal 70114 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 literal 0 HcmV?d00001 diff --git a/tests/models/test_components.py b/tests/models/test_components.py index 2accd367..8b5ed797 100644 --- a/tests/models/test_components.py +++ b/tests/models/test_components.py @@ -3,64 +3,22 @@ from pytest import param from sklearn.linear_model import LogisticRegression -import flama from flama.models.components import Model, ModelComponentBuilder class TestCaseModelComponent: - @pytest.fixture - def tensorflow_model(self): - tf_model = tf.keras.models.Sequential( - [ - tf.keras.layers.Flatten(input_shape=(28, 28)), - tf.keras.layers.Dense(128, activation="relu"), - tf.keras.layers.Dropout(0.2), - tf.keras.layers.Dense(10, activation="softmax"), - ] - ) - - tf_model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"]) - - return tf_model - - @pytest.fixture - def sklearn_model(self): - return LogisticRegression() - - @pytest.fixture - def tensorflow_dump(self, tensorflow_model): - return flama.dumps("tensorflow", tensorflow_model) - - @pytest.fixture - def sklearn_dump(self, sklearn_model): - return flama.dumps("sklearn", sklearn_model) - - @pytest.fixture(scope="function") - def model(self, request, sklearn_model, tensorflow_model): - if request.param == "tensorflow": - return tensorflow_model - - if request.param == "sklearn": - return sklearn_model - - raise ValueError("Unknown model") - - @pytest.fixture(scope="function") - def dump(self, request, sklearn_dump, tensorflow_dump): - if request.param == "tensorflow": - return tensorflow_dump - - if request.param == "sklearn": - return sklearn_dump - - raise ValueError("Unknown model") - @pytest.mark.parametrize( - ("dump", "model"), (param("tensorflow", "tensorflow"), param("sklearn", "sklearn")), indirect=["dump", "model"] + ("model_file", "model"), + ( + param("tests/models/tensorflow_model.flm", tf.keras.models.Sequential, id="tensorflow"), + param("tests/models/sklearn_model.flm", LogisticRegression, id="sklearn"), + ), ) - def test_build(self, dump, model): - component = ModelComponentBuilder.loads(dump) + def test_build(self, model_file, model): + with open(model_file, "rb") as f: + component = ModelComponentBuilder.loads(f.read()) + model_wrapper = component.model model_instance = model_wrapper.model assert isinstance(model_wrapper, Model) - assert isinstance(model_instance, model.__class__) + assert isinstance(model_instance, model) diff --git a/tests/models/test_resource.py b/tests/models/test_resource.py new file mode 100644 index 00000000..9c60778d --- /dev/null +++ b/tests/models/test_resource.py @@ -0,0 +1,192 @@ +import pytest +from pytest import param + + +class TestCaseModelResource: + @pytest.fixture(scope="function", autouse=True) + def add_models(self, app): + app.models.add_model("/tensorflow/", model="tests/models/tensorflow_model.flm", name="tensorflow") + app.models.add_model("/sklearn/", model="tests/models/sklearn_model.flm", name="sklearn") + + @pytest.mark.parametrize( + ("url", "output"), + ( + param( + "/tensorflow/", + { + "class_name": "Sequential", + "config": { + "name": "sequential_1", + "layers": [ + { + "class_name": "InputLayer", + "config": { + "batch_input_shape": [None, 1], + "dtype": "float32", + "sparse": False, + "ragged": False, + "name": "dense_3_input", + }, + }, + { + "class_name": "Dense", + "config": { + "name": "dense_3", + "trainable": True, + "batch_input_shape": [None, 1], + "dtype": "float32", + "units": 200, + "activation": "linear", + "use_bias": True, + "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": None}}, + "bias_initializer": {"class_name": "Zeros", "config": {}}, + "kernel_regularizer": None, + "bias_regularizer": None, + "activity_regularizer": None, + "kernel_constraint": None, + "bias_constraint": None, + }, + }, + { + "class_name": "Activation", + "config": { + "name": "activation_2", + "trainable": True, + "dtype": "float32", + "activation": "relu", + }, + }, + { + "class_name": "Dense", + "config": { + "name": "dense_4", + "trainable": True, + "dtype": "float32", + "units": 45, + "activation": "linear", + "use_bias": True, + "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": None}}, + "bias_initializer": {"class_name": "Zeros", "config": {}}, + "kernel_regularizer": None, + "bias_regularizer": None, + "activity_regularizer": None, + "kernel_constraint": None, + "bias_constraint": None, + }, + }, + { + "class_name": "Activation", + "config": { + "name": "activation_3", + "trainable": True, + "dtype": "float32", + "activation": "relu", + }, + }, + { + "class_name": "Dense", + "config": { + "name": "dense_5", + "trainable": True, + "dtype": "float32", + "units": 1, + "activation": "linear", + "use_bias": True, + "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": None}}, + "bias_initializer": {"class_name": "Zeros", "config": {}}, + "kernel_regularizer": None, + "bias_regularizer": None, + "activity_regularizer": None, + "kernel_constraint": None, + "bias_constraint": None, + }, + }, + ], + }, + "keras_version": "2.9.0", + "backend": "tensorflow", + }, + id="tensorflow", + ), + param( + "/sklearn/", + { + "C": 1.0, + "class_weight": None, + "dual": False, + "fit_intercept": True, + "intercept_scaling": 1, + "l1_ratio": None, + "max_iter": 100, + "multi_class": "auto", + "n_jobs": None, + "penalty": "l2", + "random_state": None, + "solver": "lbfgs", + "tol": 0.0001, + "verbose": 0, + "warm_start": False, + }, + id="sklearn", + ), + ), + ) + def test_inspect(self, client, url, output): + response = client.get(url) + assert response.status_code == 200, response.json() + assert response.json() == output + + @pytest.mark.parametrize( + ("url", "x", "y"), + ( + param( + "/tensorflow/predict/", + [ + [0.0], + [0.1111111111111111], + [0.2222222222222222], + [0.3333333333333333], + [0.4444444444444444], + [0.5555555555555556], + [0.6666666666666666], + [0.7777777777777777], + [0.8888888888888888], + [1.0], + ], + [ + [-0.18502992391586304], + [-0.19394135475158691], + [-0.21624590456485748], + [-0.23871256411075592], + [-0.25075840950012207], + [-0.21501532196998596], + [-0.038977280259132385], + [0.13738776743412018], + [0.31375277042388916], + [0.4901178479194641], + ], + id="tensorflow", + ), + param( + "/sklearn/predict/", + [ + [550.0, 2.3, 4.0], + [620.0, 3.3, 2.0], + [670.0, 3.3, 6.0], + [680.0, 3.9, 4.0], + [610.0, 2.7, 3.0], + [610.0, 3.0, 1.0], + [650.0, 3.7, 6.0], + [690.0, 3.7, 5.0], + [540.0, 2.7, 2.0], + [660.0, 3.3, 5.0], + ], + [0, 0, 1, 1, 0, 0, 1, 1, 0, 1], + id="sklearn", + ), + ), + ) + def test_predict(self, client, url, x, y): + response = client.post(url, json={"input": x}) + assert response.status_code == 200, response.json() + assert response.json() == {"output": y} diff --git a/tests/resources/test_resource.py b/tests/resources/test_resource.py index 83651e64..0bf6c60e 100644 --- a/tests/resources/test_resource.py +++ b/tests/resources/test_resource.py @@ -249,6 +249,6 @@ def foo(x: int): assert hasattr(foo, "_meta") assert foo._meta.path == "/" - assert foo._meta.methods == ["POST"] + assert foo._meta.methods == ("POST",) assert foo._meta.name == "foo" assert foo._meta.kwargs == {"additional": "bar"}