Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Revert "Remove old triton upload" #77

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,20 @@ dataset.upload_dataset(task="text_clf", split="train", module_dir="path_to_imdb_


## Model upload examples

There is an exciting new model upload experience now in private preview. We'd love for you to try it out and give us feedback! If you're interested, please sign up for private preview [here](https://forms.gle/MSx7QNxmug2oFZYD6).
### How to start
Please refer to this [doc](https://github.com/Clarifai/clarifai-python/tree/master/clarifai/models/model_serving)
### Examples
| Model type | Example |
| ----------- | ----------- |
| [multimodal-embedder](./model_upload/multimodal_embedder/) | [CLIP](./model_upload/multimodal_embedder/clip/) |
| [text-classifier](./model_upload/text_classifier) | [xlm-roberta](./model_upload/text_classifier/xlm-roberta/) |
| [text-embedder](./model_upload/text_embedder/) | [instructor-xl](./model_upload/text_embedder/instructor-xl/) |
| [text-to-image](./model_upload/text_to_image/) | [sd-v1.5](./model_upload/text_to_image/sd-v1.5/) |
| [text-to-text](./model_upload/text_to_text/) | [bart-summarize](./model_upload/text_to_text/bart-summarize/), [vllm model](./model_upload/vllm_text_to_text/example/) |
| [visual_classsifier](./model_upload/visual_classsifier/) | [age_vit](./model_upload/visual_classsifier/age_vit/) |
| [visual_detector](./model_upload/visual_detector/) | [yolof](./model_upload/visual_detector/yolof/), [faster-rcnn_torchserve](./model_upload/visual_detector/faster-rcnn_torchserve/) |
| [visual_embedder](./model_upload/visual_embedder) | [vit-base](./model_upload/visual_embedder/vit-base/) |
| [visual_segmenter](./model_upload/visual_segmenter) | [segformer-b2](./model_upload/visual_segmenter/segformer-b2/) |


## Note
Expand Down
19 changes: 19 additions & 0 deletions model_upload/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
## Clarifai Model Upload Examples

A collection of pre-built models for different tasks. To run inference locally using any of the examples here, some models may require other files such as checkpoints be downloaded before testing and/or deployment to Clarifai as they are ommitted here due to github file size limits.

See the Readme files under each model to see detail instruction of how to download the additional files and deploy the models.

## Prerequisite

Install latest `clarifai`

```bash
pip install --upgrade clarifai
```

Login to the platform for uploading model

```
clarifai login
```
39 changes: 39 additions & 0 deletions model_upload/multimodal_embedder/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Multimodal Embedder Model Examples

These can be used on the fly with minimal or no changes to test deploy image classification models to the Clarifai platform. See the required files section for each model below.

* ### [CLIP](./clip/)

Required files to run tests locally:

Download the [model checkpoint from huggingface](https://huggingface.co/openai/clip-vit-base-patch32) and store it under `clip/checkpoint/`


```
$ pip install huggingface-hub
$ huggingface-cli download openai/clip-vit-base-patch32 --local-dir clip/checkpoint/ --local-dir-use-symlinks False --exclude *.msgpack *.h5
```

Install dependecies to test locally

```bash
$ pip install -r clip/requirements.txt
```

Deploy the model to Clarifai:

>Note: set `--no-test` flag for `build` and `upload` command to disable testing

1. Build

```bash
$ clarifai build model ./clip
```

upload `*.clarifai` file to storage to obtain direct download url

2. Upload

```bash
$ clarifai upload model ./clip --url <your_url>
```
31 changes: 31 additions & 0 deletions model_upload/multimodal_embedder/clip/clarifai_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Sample config of inference_parameters and labels
# For detail, please refer to docs
# --------------------
# inference_parameters:
# - path: boolean_var
# default_value: true
# field_type: 1
# description: a boolean variable
# - path: string_var
# default_value: "a string"
# field_type: 2
# description: a string variable
# - path: number_var
# default_value: 1
# field_type: 3
# description: a number variable
# - path: secret_string_var
# default_value: "YOUR_SECRET"
# field_type: 21
# description: a string variable contains secret like API key

clarifai_model:
clarifai_model_id: ''
clarifai_user_app_id: ''
description: ''
inference_parameters: []
labels: []
type: multimodal-embedder
serving_backend:
triton:
max_batch_size: 4
62 changes: 62 additions & 0 deletions model_upload/multimodal_embedder/clip/inference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# User model inference script.

import os
from pathlib import Path
from typing import Dict, Union
from clarifai.models.model_serving.model_config import * # noqa
import torch
from transformers import CLIPModel, CLIPProcessor

class InferenceModel(MultiModalEmbedder):
"""User model inference class."""

def __init__(self) -> None:
"""
Load inference time artifacts that are called frequently .e.g. models, tokenizers, etc.
in this method so they are loaded only once for faster inference.
"""
# current directory
self.base_path: Path = os.path.dirname(__file__)
# local checkpoint for openai/clip-vit-base-patch32
self.model = CLIPModel.from_pretrained(os.path.join(self.base_path, "checkpoint"))
self.model.eval()
self.processor = CLIPProcessor.from_pretrained(os.path.join(self.base_path, "checkpoint"))

def predict(self, input_data: list,
inference_parameters: Dict[str, Union[str, float, int, bool]] = {}) -> list:
""" Custom prediction function for `multimodal-embedder` model.

Args:
input_data (List[_MultiModalInputTypeDict]): List of dict of key-value: `image`(np.ndarray) and `text` (str)
inference_parameters (Dict[str, Union[str, float, int, bool]]): your inference parameters

Returns:
list of EmbeddingOutput

"""

outputs = []
for inp in input_data:
image, text = inp.get("image", None), inp.get("text", None)
with torch.no_grad():
inputs = self.processor(text=text, images=image, return_tensors="pt", padding=True)
if text is not None:
inputs = self.processor(text=text, return_tensors="pt", padding=True)
embeddings = self.model.get_text_features(**inputs)
else:
inputs = self.processor(images=image, return_tensors="pt", padding=True)
embeddings = self.model.get_image_features(**inputs)
embeddings = embeddings.squeeze().cpu().numpy()
outputs.append(EmbeddingOutput(embedding_vector=embeddings))

return outputs


if __name__ == "__main__":

# Dummy test
model = InferenceModel()
input = dict(text="Hi")

output = model.predict([input])
print(output[0])
4 changes: 4 additions & 0 deletions model_upload/multimodal_embedder/clip/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
clarifai
tritonclient[all]
transformers==4.38.0
torch==2.1.1
40 changes: 40 additions & 0 deletions model_upload/multimodal_embedder/clip/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import unittest

from clarifai.models.model_serving.repo_build import BaseTest


class CustomTest(unittest.TestCase):
"""
BaseTest loads the InferenceModel from the inference.py file in the current working directory.
To execute the predict method of the InferenceModel, use the predict method in BaseTest.
It takes the exact same inputs and inference parameters, returning the same outputs as InferenceModel.predict.
The difference is that BaseTest.predict verifies your_infer_parameters against config.clarifai_models.inference_parameters and checks the output values.

For example, test input value of visual-classifier

def test_input(self):
import cv2
path = "path/to/image"
img = cv2.imread(path)
outputs = self.model.predict([img], infer_param1=..., infer_param2=...)
print(outputs)
assert outputs

"""

def setUp(self) -> None:
your_infer_parameter = dict(
) # for example dict(float_var=0.12, string_var="test", _secret_string_var="secret")
self.model = BaseTest(your_infer_parameter)

def test_default_cases(self):
"""Test your model with dummy inputs.
In general, you only need to run this test to check your InferneceModel implementation.
In case the default inputs makes your model failed for some reason (not because of assert in `test_with_default_inputs`),
you can comment out this test.
"""
self.model.test_with_default_inputs()

def test_specific_case1(self):
""" Implement your test case"""
pass
39 changes: 39 additions & 0 deletions model_upload/text_classifier/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Text Classification Model Examples

These can be used on the fly with minimal or no changes to test deploy text classification models to the Clarifai platform. See the required files section for each model below.

* ### [XLM-Roberta Tweet Sentiment Classifier](./xlm-roberta/)

Required files to run tests locally:

Download the [model checkpoint](https://huggingface.co/cardiffnlp/twitter-xlm-roberta-base-sentiment/tree/main) and store it under `xlm-roberta/checkpoint/`

```
$ pip install huggingface-hub
$ huggingface-cli download cardiffnlp/twitter-xlm-roberta-base-sentiment --local-dir xlm-roberta/checkpoint/ --local-dir-use-symlinks False --exclude *.msgpack *.h5
```

Install dependecies to test locally

```bash
$ pip install -r xlm-roberta/requirements.txt
```

Deploy the model to Clarifai:

>Note: set `--no-test` flag for `build` and `upload` command to disable testing

1. Build

```bash
$ clarifai build model ./xlm-roberta
```

upload `*.clarifai` file to storage to obtain direct download url

2. Upload

```bash
$ clarifai upload model ./xlm-roberta --url <your_url>
```

13 changes: 13 additions & 0 deletions model_upload/text_classifier/xlm-roberta/clarifai_config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
clarifai_model:
clarifai_model_id: ''
clarifai_user_app_id: ''
description: ''
inference_parameters: []
labels:
- Negative
- Neutral
- Positive
type: text-classifier
serving_backend:
triton:
max_batch_size: 4
56 changes: 56 additions & 0 deletions model_upload/text_classifier/xlm-roberta/inference.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# User model inference script.

import os
from pathlib import Path
from typing import Dict, Union
from clarifai.models.model_serving.model_config import * # noqa

import torch
from scipy.special import softmax
from transformers import AutoModelForSequenceClassification, AutoTokenizer

class InferenceModel(TextClassifier):
"""User model inference class."""

def __init__(self) -> None:
"""
Load inference time artifacts that are called frequently .e.g. models, tokenizers, etc.
in this method so they are loaded only once for faster inference.
"""
# current directory
self.base_path: Path = os.path.dirname(__file__)
self.checkpoint_path: Path = os.path.join(self.base_path, "checkpoint")
self.model = AutoModelForSequenceClassification.from_pretrained(self.checkpoint_path)
self.tokenizer = AutoTokenizer.from_pretrained(self.checkpoint_path)

def predict(self, input_data: list,
inference_parameters: Dict[str, Union[str, float, int]]) -> list:
""" Custom prediction function for `text-classifier` model.

Args:
input_data (List[str]): List of text
inference_parameters (Dict[str, Union[str, float, int]]): your inference parameters

Returns:
list of ClassifierOutput

"""

outputs = []
for inp in input_data:
encoded_input = self.tokenizer(inp, return_tensors='pt')
output = self.model(**encoded_input)
scores = output[0][0].detach().numpy()
scores = softmax(scores)
outputs.append(ClassifierOutput(predicted_scores=scores))

return outputs

if __name__ == "__main__":

# Dummy test
model = InferenceModel()
input = "How are you today?"

output = model.predict([input])
print(output[0])
7 changes: 7 additions & 0 deletions model_upload/text_classifier/xlm-roberta/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
clarifai
tritonclient[all]
torch==1.13.1
transformers==4.38.0
scipy==1.10.1
sentencepiece==0.1.99
protobuf<4.21.3
40 changes: 40 additions & 0 deletions model_upload/text_classifier/xlm-roberta/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import unittest

from clarifai.models.model_serving.repo_build import BaseTest


class CustomTest(unittest.TestCase):
"""
BaseTest loads the InferenceModel from the inference.py file in the current working directory.
To execute the predict method of the InferenceModel, use the predict method in BaseTest.
It takes the exact same inputs and inference parameters, returning the same outputs as InferenceModel.predict.
The difference is that BaseTest.predict verifies your_infer_parameters against config.clarifai_models.inference_parameters and checks the output values.

For example, test input value of visual-classifier

def test_input(self):
import cv2
path = "path/to/image"
img = cv2.imread(path)
outputs = self.model.predict([img], infer_param1=..., infer_param2=...)
print(outputs)
assert outputs

"""

def setUp(self) -> None:
your_infer_parameter = dict(
) # for example dict(float_var=0.12, string_var="test", _secret_string_var="secret")
self.model = BaseTest(your_infer_parameter)

def test_default_cases(self):
"""Test your model with dummy inputs.
In general, you only need to run this test to check your InferneceModel implementation.
In case the default inputs makes your model failed for some reason (not because of assert in `test_with_default_inputs`),
you can comment out this test.
"""
self.model.test_with_default_inputs()

def test_specific_case1(self):
""" Implement your test case"""
pass
Loading