Skip to content

Commit 64b7b4b

Browse files
Merge pull request #1325 from roboflow/perception-encoder
feat: add PerceptionEncoder model implementation with tests
2 parents 2998c99 + cc52439 commit 64b7b4b

17 files changed

Lines changed: 821 additions & 16 deletions

.github/workflows/integration_tests_inference_cli_depending_on_inference_x86.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ jobs:
3838
- name: 📦 Install dependencies
3939
run: |
4040
python -m pip install --upgrade pip
41-
pip install --upgrade setuptools
42-
pip install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.yolo_world.txt -r requirements/requirements.doctr.txt -r requirements/requirements.sam.txt -r requirements/requirements.transformers.txt -r requirements/requirements.cli.txt -r requirements/requirements.sdk.http.txt
41+
pip install uv
42+
uv pip install --system --upgrade setuptools
43+
uv pip install --system --extra-index-url https://download.pytorch.org/whl/cpu -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.yolo_world.txt -r requirements/requirements.doctr.txt -r requirements/requirements.sam.txt -r requirements/requirements.transformers.txt -r requirements/requirements.cli.txt -r requirements/requirements.sdk.http.txt
4344
- name: 🧪 Integration Tests of Inference CLI
4445
run: RUN_TESTS_WITH_INFERENCE_PACKAGE=True INFERENCE_CLI_TESTS_API_KEY=${{ secrets.LOAD_TEST_PRODUCTION_API_KEY }} python -m pytest tests/inference_cli/integration_tests/test_workflows.py

.github/workflows/integration_tests_inference_cli_x86.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ jobs:
3838
- name: 📦 Install dependencies
3939
run: |
4040
python -m pip install --upgrade pip
41-
pip install --upgrade setuptools
42-
pip install -r requirements/requirements.cli.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt
41+
pip install uv
42+
uv pip install --system --upgrade setuptools
43+
uv pip install --system -r requirements/requirements.cli.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt
4344
- name: 🧪 Integration Tests of Inference CLI
4445
run: RUN_TESTS_EXPECTING_ERROR_WHEN_INFERENCE_NOT_INSTALLED=True INFERENCE_CLI_TESTS_API_KEY=${{ secrets.LOAD_TEST_PRODUCTION_API_KEY }} python -m pytest tests/inference_cli/integration_tests

.github/workflows/integration_tests_inference_models.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ jobs:
4040
- name: 📦 Install dependencies
4141
run: |
4242
python -m pip install --upgrade pip
43-
pip install --upgrade setuptools
44-
pip install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.yolo_world.txt -r requirements/requirements.sam.txt -r requirements/requirements.transformers.txt
43+
pip install uv
44+
uv pip install --system --upgrade setuptools
45+
uv pip install --system --extra-index-url https://download.pytorch.org/whl/cpu -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.yolo_world.txt -r requirements/requirements.sam.txt -r requirements/requirements.transformers.txt
4546
- name: 🧪 Integration Tests of Inference models
4647
timeout-minutes: 45
4748
run: MAX_BATCH_SIZE=6 python -m pytest tests/inference/models_predictions_tests

.github/workflows/integration_tests_workflows_x86.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ jobs:
4242
- name: 📦 Install dependencies
4343
run: |
4444
python -m pip install --upgrade pip
45-
pip install --upgrade setuptools
46-
pip install --extra-index-url https://download.pytorch.org/whl/cpu -r requirements/_requirements.txt -r requirements/requirements.sam.txt -r requirements/requirements.cpu.txt -r requirements/requirements.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.doctr.txt -r requirements/requirements.yolo_world.txt -r requirements/requirements.transformers.txt -r requirements/requirements.sdk.http.txt
45+
pip install uv
46+
uv pip install --system --upgrade setuptools
47+
uv pip install --system --extra-index-url https://download.pytorch.org/whl/cpu --index-strategy unsafe-best-match -r requirements/_requirements.txt -r requirements/requirements.sam.txt -r requirements/requirements.cpu.txt -r requirements/requirements.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.doctr.txt -r requirements/requirements.yolo_world.txt -r requirements/requirements.transformers.txt -r requirements/requirements.sdk.http.txt
4748
- name: 🧪 Integration Tests of Workflows
4849
run: ROBOFLOW_API_KEY=${{ secrets.API_KEY }} SKIP_FLORENCE2_TEST=FALSE LOAD_ENTERPRISE_BLOCKS=TRUE python -m pytest tests/workflows/integration_tests

.github/workflows/unit_tests_inference_cli_x86.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ jobs:
4040
- name: 📦 Install dependencies
4141
run: |
4242
python -m pip install --upgrade pip
43-
pip install --upgrade setuptools
44-
pip install -r requirements/requirements.cli.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.sdk.http.txt
43+
pip install uv
44+
uv pip install --system --upgrade setuptools
45+
uv pip install --system -r requirements/requirements.cli.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.sdk.http.txt
4546
- name: 🧪 Unit Tests of Inference CLI
4647
timeout-minutes: 30
4748
run: python -m pytest tests/inference_cli/unit_tests

.github/workflows/unit_tests_inference_sdk_x86.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@ jobs:
4040
- name: 📦 Install dependencies
4141
run: |
4242
python -m pip install --upgrade pip
43-
pip install --upgrade setuptools
44-
pip install -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt
43+
pip install uv
44+
uv pip install --system --upgrade setuptools
45+
uv pip install --system -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt
4546
- name: 🧪 Unit Tests of Inference SDK
4647
timeout-minutes: 30
4748
run: python -m pytest tests/inference_sdk/unit_tests

.github/workflows/unit_tests_inference_x86.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ jobs:
4141
- name: 📦 Install dependencies
4242
run: |
4343
python -m pip install --upgrade pip
44-
pip install --upgrade setuptools
45-
pip install -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.transformers.txt
44+
pip install uv
45+
uv pip install --system --upgrade setuptools
46+
uv pip install --system -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.transformers.txt
4647
- name: 🧪 Unit Tests of Inference
4748
timeout-minutes: 30
4849
run: python -m pytest tests/inference/unit_tests

.github/workflows/unit_tests_workflows_x86.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ jobs:
4141
- name: 📦 Install dependencies
4242
run: |
4343
python -m pip install --upgrade pip
44-
pip install --upgrade setuptools
45-
pip install -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.transformers.txt
44+
pip install uv
45+
uv pip install --system --upgrade setuptools
46+
uv pip install --system -r requirements/_requirements.txt -r requirements/requirements.cpu.txt -r requirements/requirements.sdk.http.txt -r requirements/requirements.test.unit.txt -r requirements/requirements.http.txt -r requirements/requirements.transformers.txt
4647
- name: 🧪 Unit Tests of Workflows
4748
timeout-minutes: 30
4849
run: python -m pytest tests/workflows/unit_tests
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
<a href="https://github.com/facebookresearch/perception_models?tab=readme-ov-file#perception-encoder-pe" target="_blank">Perception Encoder</a> is a computer vision model that can measure the similarity between text and images, as well as compute useful text and image embeddings.
2+
3+
Perception Encoder embeddings can be used for, among other things:
4+
5+
- Image classification
6+
- Image clustering
7+
- Gathering images for model training that are sufficiently dissimilar from existing samples
8+
- Content moderation
9+
10+
With Inference, you can calculate PE embeddings for images and text in real-time.
11+
12+
In this guide, we will show:
13+
14+
1. How to classify video frames with PE in real time, and;
15+
2. How to calculate PE image and text embeddings for use in clustering and comparison.
16+
17+
## How can I use PE in `inference`?
18+
19+
- directly from `inference[transformers]` package, integrating the model directly into your code
20+
- using `inference` HTTP API (hosted locally, or on the Roboflow platform), integrating via HTTP protocol
21+
- using `inference-sdk` package (`pip install inference-sdk`) and [`InferenceHTTPClient`](../inference_helpers/inference_sdk.md)
22+
- creating custom code to make HTTP requests (see [API Reference](/api))
23+
24+
## Supported PE versions
25+
26+
- `perception_encoder/PE-Core-B16-224`
27+
- `perception_encoder/PE-Core-L14-336`
28+
- `perception_encoder/PE-Core-G14-448`
29+
30+
We currently only support the CLIP interface for PE models. We don't support the language or spatial aligned models yet.
31+
32+
## Classify Video Frames
33+
34+
With PE, you can classify images and video frames without training a model. This is because PE has been pre-trained to recognize many different objects.
35+
36+
To use PE to classify video frames, you need a prompt. In the example below, we will use the prompt "an image of a guy with a beard holding a can of sparkling water".
37+
38+
We can compare the similarity of the prompt to each video frame and use that to classify the video frame.
39+
40+
Below is a demo of PE classifying video frames in real time. The code for the example is below the image.
41+
42+
<img src="https://storage.googleapis.com/com-roboflow-marketing/inference/pe2.png" alt="Perception Encoder demo" width="800"/>
43+
44+
45+
First, install the Inference transformers extension:
46+
47+
```
48+
pip install "inference[transformers]"
49+
```
50+
51+
Then, create a new Python file and add the following code:
52+
53+
```python
54+
import cv2
55+
import inference
56+
from inference.core.utils.postprocess import cosine_similarity
57+
58+
from inference.models import PerceptionEncoder
59+
pe = PerceptionEncoder(model_id="perception_encoder/PE-Core-B16-224", device="mps") # `model_id` has default, but here is how to test other versions
60+
61+
prompt = "an image of a guy with a beard holding a can of sparkling water"
62+
text_embedding = pe.embed_text(prompt)
63+
64+
def render(result, image):
65+
# get the cosine similarity between the prompt & the image
66+
similarity = cosine_similarity(result["embeddings"][0], text_embedding[0])
67+
68+
# scale the result to 0-100 based on heuristic (~the best & worst values I've observed)
69+
range = (0.15, 0.40)
70+
similarity = (similarity-range[0])/(range[1]-range[0])
71+
similarity = max(min(similarity, 1), 0)*100
72+
73+
# print the similarity
74+
text = f"{similarity:.1f}%"
75+
cv2.putText(image, text, (10, 310), cv2.FONT_HERSHEY_SIMPLEX, 12, (255, 255, 255), 30)
76+
cv2.putText(image, text, (10, 310), cv2.FONT_HERSHEY_SIMPLEX, 12, (206, 6, 103), 16)
77+
78+
# print the prompt
79+
cv2.putText(image, prompt, (20, 1050), cv2.FONT_HERSHEY_SIMPLEX, 2, (255, 255, 255), 10)
80+
cv2.putText(image, prompt, (20, 1050), cv2.FONT_HERSHEY_SIMPLEX, 2, (206, 6, 103), 5)
81+
82+
# display the image
83+
cv2.imshow("PE", image)
84+
cv2.waitKey(1)
85+
86+
# start the stream
87+
inference.Stream(
88+
source="webcam",
89+
model=pe,
90+
output_channel_order="BGR",
91+
use_main_thread=True,
92+
on_prediction=render
93+
)
94+
```
95+
96+
Run the code to use Perception Encoder on your webcam.
97+
98+
**Note:** The model will take a minute or two to load. You will not see output while the model is loading.
99+
100+
## API Compatibility
101+
102+
The Perception Encoder model uses the **same API as CLIP**. This means you can use all the same methods and request/response formats as you would with CLIP, including `embed_text`, `embed_image`, and `compare`.
103+
104+
For more details and advanced usage, see the [CLIP documentation](./clip.md).

inference/core/env.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,14 @@
8282
# CLIP model ID
8383
CLIP_MODEL_ID = f"clip/{CLIP_VERSION_ID}"
8484

85+
# Perception Encoder version ID, default is "PE-Core-L14-336"
86+
PERCEPTION_ENCODER_VERSION_ID = os.getenv(
87+
"PERCEPTION_ENCODER_VERSION_ID", "PE-Core-L14-336"
88+
)
89+
90+
# Perception Encoder model ID
91+
PERCEPTION_ENCODER_MODEL_ID = f"perception-encoder/{PERCEPTION_ENCODER_VERSION_ID}"
92+
8593
# Gaze version ID, default is "L2CS"
8694
GAZE_VERSION_ID = os.getenv("GAZE_VERSION_ID", "L2CS")
8795

0 commit comments

Comments
 (0)