예제 #1
0
    def ResNet50(framework: Framework, version: str = '1', enable_trt=False):
        """Export, generate model family and register ResNet50

        Arguments:
            framework (Framework): Framework name.
            version (str): Model version.
            enable_trt (bool): Flag for enabling TRT conversion.
        """
        if framework == Framework.TENSORFLOW:
            model = tf.keras.applications.ResNet50()
            # converting to trt

            if not enable_trt:
                tfs_dir = generate_path(model_name='ResNet50',
                                        framework=framework,
                                        task=Task.IMAGE_CLASSIFICATION,
                                        engine=Engine.TFS,
                                        version=str(version))
                TFSConverter.from_tf_model(model, tfs_dir)
                model = str(tfs_dir.with_suffix('.zip'))

            register_model(
                model,
                dataset='imagenet',
                metric={Metric.ACC: 0.76},
                task=Task.IMAGE_CLASSIFICATION,
                inputs=[
                    IOShape([-1, 224, 224, 3],
                            dtype=float,
                            name='input_1',
                            format=ModelInputFormat.FORMAT_NHWC)
                ],
                outputs=[IOShape([-1, 1000], dtype=float, name='probs')],
                architecture='ResNet50',
                framework=framework,
                version=ModelVersion(version),
                convert=enable_trt,
            )
        elif framework == Framework.PYTORCH:
            model = models.resnet50(pretrained=True)
            register_model(
                model,
                dataset='imagenet',
                metric={Metric.ACC: 0.76},
                task=Task.IMAGE_CLASSIFICATION,
                inputs=[
                    IOShape([-1, 3, 224, 224],
                            dtype=float,
                            name='INPUT__0',
                            format=ModelInputFormat.FORMAT_NCHW)
                ],
                outputs=[IOShape([-1, 1000], dtype=float, name='probs')],
                architecture='ResNet50',
                framework=framework,
                version=ModelVersion(version),
            )
        else:
            raise ValueError('Framework not supported.')
예제 #2
0
 def setUpClass(cls):
     cls.torch_model = torchvision.models.alexnet(pretrained=True)
     cls.inputs = [
         IOShape([1, 3, 224, 224],
                 dtype=float,
                 name='INPUT__0',
                 format=ModelInputFormat.FORMAT_NCHW)
     ]
     cls.outputs = [IOShape([-1, 1000], dtype=float, name='probs')]
     cls.X = torch.rand(1, 3, 224, 224, dtype=torch.float32)
     cls.onnx_path = Path(tempfile.gettempdir() + '/test.onnx')
     cls.torchscript_path = Path(tempfile.gettempdir() +
                                 '/test_torchscript.zip')
예제 #3
0
def test_onnx_to_pytorch():
    onnx_model = ONNXConverter.from_sklearn(sklearn_model,
                                            inputs_bc,
                                            optimize=False)
    inputs = list()
    for input_ in onnx_model.graph.input:
        name = input_.name
        t = input_.type.tensor_type
        shape = list()
        if t.HasField('shape'):
            for d in t.shape.dim:
                if d.HasField('dim_value'):
                    shape.append(d.dim_value)
                elif d.HasField('dim_param'):
                    shape.append(d.dim_param)
                else:
                    shape.append(-1)
        dtype = t.elem_type
        inputs.append(IOShape(name=name, dtype=dtype, shape=shape))

    dtype = model_data_type_to_torch(inputs[0].dtype)
    sample_input = torch.rand([2, *inputs[0].shape[1:]], dtype=dtype)
    model = PyTorchConverter.from_onnx(onnx_model)

    model(sample_input)
예제 #4
0
def test_register_model():
    model = ModelBO('ResNet50',
                    framework=Framework.PYTORCH,
                    engine=Engine.TRT,
                    version=ModelVersion(1),
                    dataset='ImageNet',
                    acc=0.8,
                    task='image classification',
                    inputs=[
                        IOShape([-1, 3, 224, 224],
                                dtype=float,
                                format=ModelInputFormat.FORMAT_NCHW)
                    ],
                    outputs=[IOShape([-1, 1000], dtype=int)],
                    weight=Weight(bytes([123])))

    assert ModelService.post_model(model)
예제 #5
0
 def setUpClass(cls):
     cls.keras_model = tf.keras.applications.ResNet50()
     cls.sample_input = np.random.random((1, 224, 224, 3)).astype('float32')
     cls.keras_model_predict = cls.keras_model.predict(cls.sample_input)
     cls.tfs_model_path = Path(
         tempfile.gettempdir() +
         '/ResNet50/tensorflow-tfs/image_classification/1')
     cls.trt_model_path = Path(
         tempfile.gettempdir() +
         '/ResNet50/tensorflow-trt/image_classification/1')
     cls.inputs = [
         IOShape([-1, 224, 224, 3],
                 dtype=float,
                 name='input_1',
                 format=ModelInputFormat.FORMAT_NHWC)
     ]
     cls.outputs = [IOShape([-1, 1000], dtype=float, name='probs')]
예제 #6
0
def test_register_model():
    model = ModelBO('ResNet50',
                    framework=Framework.PYTORCH,
                    engine=Engine.TRT,
                    version=ModelVersion(1),
                    dataset='ImageNet',
                    metric={Metric.ACC: 0.80},
                    task=Task.IMAGE_CLASSIFICATION,
                    inputs=[
                        IOShape([-1, 3, 224, 224],
                                dtype=float,
                                format=ModelInputFormat.FORMAT_NCHW)
                    ],
                    outputs=[IOShape([-1, 1000], dtype=int)],
                    weight=Weight(bytes([123])))

    assert ModelService.post_model(model)
예제 #7
0
 def setUpClass(cls):
     num_classes = 2
     X = np.random.rand(100000, 28).astype(np.float32)
     y = np.random.randint(num_classes, size=100000)
     cls.lgbm_model = lgb.LGBMClassifier()
     cls.lgbm_model.fit(X, y)
     cls.inputs = [IOShape(shape=[-1, 28], dtype=X.dtype, name='input_0')]
     cls.sample_input = X[0:2, :]
     cls.lgbm_model_out = cls.lgbm_model.predict(cls.sample_input)
     cls.lgbm_model_probs = cls.lgbm_model.predict_proba(cls.sample_input)
예제 #8
0
 def setUpClass(cls):
     X_bc, y_bc = load_breast_cancer(return_X_y=True)
     nrows = 15000
     X_bc: np.ndarray = X_bc[0:nrows]
     y_bc: np.ndarray = y_bc[0:nrows]
     model = lgb.LGBMRegressor(n_estimators=3, min_child_samples=1)
     model.fit(X_bc, y_bc)
     inputs_bc = [IOShape(shape=[-1, X_bc.shape[1]], dtype=float, name='input_0')]
     cls.onnx_model = convert(model, 'lightgbm', 'onnx', inputs=inputs_bc, optimize=False)
     sess = rt.InferenceSession(cls.onnx_model.SerializeToString())
     cls.sample_input = torch.rand(2, X_bc.shape[1], dtype=torch.float32)
     cls.onnx_model_predict = sess.run(None, {'input_0': cls.sample_input.numpy()})[0].flatten()
예제 #9
0
    def setUpClass(cls):

        X_bc, y_bc = load_breast_cancer(return_X_y=True)
        nrows = 15000
        X_bc: np.ndarray = X_bc[0:nrows]
        y_bc: np.ndarray = y_bc[0:nrows]
        sklearn_model = RandomForestClassifier(n_estimators=10, max_depth=10)
        sklearn_model.fit(X_bc, y_bc)
        inputs_bc = [IOShape(shape=[-1, X_bc.shape[1]], dtype=float, name='input_0')]
        cls.onnx_model = convert(sklearn_model, 'sklearn', 'onnx', inputs=inputs_bc, optimize=False)
        sess = rt.InferenceSession(cls.onnx_model.SerializeToString())
        cls.sample_input = torch.rand(2, X_bc.shape[1], dtype=torch.float32)
        cls.onnx_model_predict = sess.run(None, {'input_0': cls.sample_input.numpy()})[0].flatten()
예제 #10
0
    def convert_ioshape_plain_to_ioshape(ioshape_plain):
        """Convert IOShape-like dictionary to IOShape.
        """
        # unpack
        i, ioshape_plain = ioshape_plain

        assert isinstance(ioshape_plain['shape'], Iterable), \
            f'inputs[{i}].shape expected to be iterable, but got {ioshape_plain["shape"]}'
        assert isinstance(ioshape_plain['dtype'], str), \
            f'inputs[{i}].dtype expected to be a `DataType`, but got {ioshape_plain["dtype"]}.'

        ioshape_plain['dtype'] = DataType[ioshape_plain['dtype']]

        return IOShape(**ioshape_plain)
예제 #11
0
 def ResNet101(framework: Framework, version: str = "1"):
     if framework == Framework.TENSORFLOW:
         model = tf.keras.applications.ResNet101()
         register_model(
             model,
             dataset='imagenet',
             acc=...,  # TODO: to be filled
             task='image classification',
             inputs=[
                 IOShape([-1, 224, 224, 3],
                         dtype=float,
                         name='input_1',
                         format=ModelInputFormat.FORMAT_NHWC)
             ],
             outputs=[IOShape([-1, 1000], dtype=float, name='probs')],
             architecture='ResNet101',
             framework=framework,
             version=ModelVersion(version))
     elif framework == Framework.PYTORCH:
         model = models.resnet101(pretrained=True)
         register_model(
             model,
             dataset='imagenet',
             acc=...,  # TODO
             task='image classification',
             inputs=[
                 IOShape([-1, 3, 224, 224],
                         dtype=float,
                         name='INPUT__0',
                         format=ModelInputFormat.FORMAT_NCHW)
             ],
             outputs=[IOShape([-1, 1000], dtype=float, name='probs')],
             architecture='ResNet101',
             framework=framework,
             version=ModelVersion(version))
     else:
         raise ValueError('Framework not supported.')
예제 #12
0
    def setUpClass(cls):
        X_bc, y_bc = load_breast_cancer(return_X_y=True)
        nrows = 15000
        X_bc: np.ndarray = X_bc[0:nrows]
        y_bc: np.ndarray = y_bc[0:nrows]

        cls.sklearn_model = RandomForestClassifier(n_estimators=10,
                                                   max_depth=10)
        cls.sklearn_model.fit(X_bc, y_bc)
        cls.inputs_bc = [
            IOShape(shape=[-1, X_bc.shape[1]], dtype=float, name='input_0')
        ]
        cls.sample_input = X_bc[0:2, :].astype(np.float32)
        cls.sklearn_model_out = cls.sklearn_model.predict(cls.sample_input)
        cls.sklearn_model_probs = cls.sklearn_model.predict_proba(
            cls.sample_input)
예제 #13
0
def update_finetune_model_as_new(id: str,
                                 updated_layer: Structure,
                                 dry_run: bool = False):  # noqa
    """
    Temporary function for finetune CV models. The function's functionality is overlapped with
    `update_model_structure_as_new`. Please use the `update_model_structure_as_new` in next release.

    Examples:
        Fine-tune the model by modify the layer with name 'fc' (last layer). The layer
        has a changed argument out_features = 10. op_='M' indicates the operation to this layer ('fc')
        is 'Modify'. There is no changes in layer connections.
        Therefore, the structure change summary is
            [M] fc: (...) out_features=10

        >>> from collections import OrderedDict
        >>> structure_data = {
        ...     'layer': OrderedDict({'fc': {'out_features': 10, 'op_': 'M', 'type_': 'torch.nn.Linear'}})
        ... }
        >>> update_finetune_model_as_new(id=..., updated_layer=Structure.parse_obj(structure_data))

    Args:
        id (str): ID of the model to be updated.
        updated_layer (Structure): Contains layers to be fine-tuned.
        dry_run (bool): Test run for verify if the provided parameter (i.e. model specified in `id`
            and updated layers) is valid.

    Returns:

    """
    if len(updated_layer.layer.items()) == 0:
        return True
    model = ModelService.get_model_by_id(id)
    if model.engine != Engine.PYTORCH:
        raise ValueError(f'model {id} is not supported for editing. '
                         f'Currently only support model with engine=PYTORCH')
    # download model as local cache
    cache_path = get_remote_model_weight(model=model)
    net = torch.load(cache_path)

    for layer_name, layer_param in updated_layer.layer.items():
        layer_op = getattr(layer_param, 'op_')

        # update layer
        if layer_op == Operation.MODIFY:

            # check if the layer name exists
            # TODO check if layer path exists eg."layer1.0.conv1"
            if not hasattr(net, layer_name):
                raise ModelStructureError(
                    f'Structure layer name `{layer_name}` not found in model {id}.'
                )
            net_layer = getattr(net, layer_name)

            # check if the provided type matches the original type
            layer_type = type(net_layer)
            layer_type_provided = eval(layer_param.type_.value)  # nosec
            if layer_type is not layer_type_provided:
                raise ModelStructureError(
                    f'Expect `{layer_name}.type_` to be {layer_type}, '
                    f'but got {layer_type_provided}')

            # get layer parameters
            layer_param_old = layer_param.parse_layer_obj(net_layer)
            layer_param_data = layer_param_old.dict(exclude_none=True,
                                                    exclude={'type_', 'op_'})

            layer_param_update_data = layer_param.dict(
                exclude_none=True, exclude={'type_', 'op_'})
            # replace 'null' with None. See reason :class:`ModelLayer`.
            for k, v in layer_param_update_data.items():
                if v == 'null':
                    layer_param_update_data[k] = None

            # update the layer parameters
            layer_param_data.update(layer_param_update_data)
            layer = layer_type(**layer_param_data)
            setattr(net, layer_name, layer)

        else:
            # if layer_op is Operation.ADD,
            #     1. check if the layer name not exists
            #     2. add a layer
            #     3. change the `forward` function according to the connections
            # if layer_op is Operation.DELETE,
            #     1. check if the layer exists
            #     2. delete the layer
            #     3. change the `forward` function
            raise ValueError(
                'Operation not permitted. Please use `update_model_structure_as_new`.'
            )

    input_tensors = list()
    bs = 1
    for input_ in model.inputs:
        input_tensor = torch.rand(bs, *input_.shape[1:]).type(
            model_data_type_to_torch(input_.dtype))
        input_tensors.append(input_tensor)

    # parse output tensors
    output_shapes = list()
    output_tensors = net(*input_tensors)
    if not isinstance(output_tensors, (list, tuple)):
        output_tensors = (output_tensors, )
    for output_tensor in output_tensors:
        output_shape = IOShape(shape=[bs, *output_tensor.shape[1:]],
                               dtype=type_to_data_type(output_tensor.dtype))
        output_shapes.append(output_shape)

    if not dry_run:
        # TODO return validation result for dry_run mode
        # TODO apply Semantic Versioning https://semver.org/
        # TODO reslove duplicate model version problem in a more efficient way
        version = ModelVersion(model.version.ver + 1)
        previous_models = ModelService.get_models(
            architecture=model.architecture,
            task=model.task,
            framework=model.framework,
            engine=Engine.NONE)
        if len(previous_models):
            last_version = max(previous_models,
                               key=lambda k: k.version.ver).version.ver
            version = ModelVersion(last_version + 1)

        saved_path = generate_path_plain(architecture=model.architecture,
                                         task=model.task,
                                         framework=model.framework,
                                         engine=Engine.NONE,
                                         version=version)
        saved_path.parent.mkdir(parents=True, exist_ok=True)
        torch.save(model, saved_path.with_suffix('.pt'))
        mlmodelin = MLModel(dataset='',
                            metric={key: 0
                                    for key in model.metric.keys()},
                            task=model.task,
                            inputs=model.inputs,
                            outputs=output_shapes,
                            architecture=model.name,
                            framework=model.framework,
                            engine=Engine.NONE,
                            model_status=[ModelStatus.DRAFT],
                            parent_model_id=model.id,
                            version=version,
                            weight=saved_path)
        register_model(mlmodelin, convert=False, profile=False)

        model_bo = ModelService.get_models(architecture=model.architecture,
                                           task=model.task,
                                           framework=model.framework,
                                           engine=Engine.NONE,
                                           version=version)[0]

        return {'id': model_bo.id}
예제 #14
0
import numpy as np
import onnx
import onnxruntime
import torch
import xgboost as xgt
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier

from modelci.hub.converter import PyTorchConverter, ONNXConverter
from modelci.types.bo import IOShape
from modelci.types.type_conversion import model_data_type_to_torch

num_classes = 2
X = np.random.rand(100000, 28).astype(np.float32)
y = np.random.randint(num_classes, size=100000)
inputs = [IOShape(shape=[-1, 28], dtype=X.dtype, name='input_0')]

xgboost_model = xgt.XGBRegressor()
xgboost_model.fit(X, y)

lgbm_model = lgb.LGBMClassifier()
lgbm_model.fit(X, y)

X_bc, y_bc = load_breast_cancer(return_X_y=True)
nrows = 15000
X_bc: np.ndarray = X_bc[0:nrows]
y_bc: np.ndarray = y_bc[0:nrows]

sklearn_model = RandomForestClassifier(n_estimators=10, max_depth=10)
sklearn_model.fit(X_bc, y_bc)
inputs_bc = [