Skip to content

Commit 6f2fd42

Browse files
committed
update readme
1 parent 072d164 commit 6f2fd42

1 file changed

Lines changed: 47 additions & 20 deletions

File tree

README.md

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,12 @@ implementation("com.github.dev-diaries41.smartscan-sdk:smartscan-ml:1.1.0")
7070

7171
## Quick Start
7272

73-
Below is information on how to get started with embedding, indexing, and searching.
73+
Below is information on how to get started with embedding, clustering, indexing, and searching.
7474

7575
### Embeddings
7676

77+
You can use bundled or downloaded models, see [docs](docs/ml/providers.md) for more details.
78+
7779
#### Text Embeddings
7880

7981
Generate vector embeddings from text strings or batches of text for tasks such as semantic search or similarity comparison.
@@ -83,18 +85,23 @@ Generate vector embeddings from text strings or batches of text for tasks such a
8385
```kotlin
8486
//import com.fpf.smartscansdk.ml.models.providers.embeddings.clip.ClipTextEmbedder
8587

86-
// Requires model to be in raw resources at e.g res/raw/text_encoder_quant_int8.onnx
87-
val textEmbedder = ClipTextEmbedder(context, ResourceId(R.raw.text_encoder_quant_int8))
88+
// downloaded model
89+
val textEmbedder = ModelManager.getTextEmbedder(application, ModelName.ALL_MINILM_L6_V2)
90+
91+
// bundled model
92+
val textEmbedder = ClipTextEmbedder(application, ModelAssetSource.Resource(R.raw.clip_text_encoder_quant), vocabSource = ModelAssetSource.Resource(R.raw.vocab), mergesSource = ModelAssetSource.Resource(R.raw.merges))
8893
val text = "Hello smartscan"
8994
val embedding = textEmbedder.embed(text)
9095

9196
```
9297

9398
**Batch Example:**
9499

100+
Specifically designed for large batches
101+
95102
```kotlin
96103
val texts = listOf("first sentence", "second sentence")
97-
val embeddings = textEmbedder.embedBatch(texts)
104+
val embeddings = embedBatch(context, textEmbedder, texts)
98105
```
99106

100107
---
@@ -108,8 +115,11 @@ Generate vector embeddings from images (as `Bitmap`) for visual search or simila
108115
```kotlin
109116
//import com.fpf.smartscansdk.ml.models.providers.embeddings.clip.ClipImageEmbedder
110117

111-
// Requires model to be in raw resources at e.g res/raw/image_encoder_quant_int8.onnx
112-
val imageEmbedder = ClipImageEmbedder(context, ResourceId(R.raw.image_encoder_quant_int8))
118+
// downloaded model
119+
val imageEmbedder = ModelManager.getImageEmbedder(application, ModelName.DINOV2_SMALL)
120+
121+
// bundled model
122+
val imageEmbedder = ClipImageEmbedder(application, ModelAssetSource.Resource(R.raw.clip_image_encoder_quant))
113123

114124
val embedding = imageEmbedder.embed(bitmap)
115125

@@ -119,23 +129,23 @@ val embedding = imageEmbedder.embed(bitmap)
119129
**Batch Example:**
120130

121131
```kotlin
122-
val images: List<Bitmap> = ...
123-
val embeddings = imageEmbedder.embedBatch(images)
132+
val images = listOf<Bitmap>()
133+
val embeddings = embedBatch(context, imageEmbedder, images)
124134
```
125135

126136
### Indexing
127137

128-
To get started with indexing media quickly, you can use the provided `ImageIndex` and `VideoIndexer` classes as shown below. You can optionally create your own indexers (including for text related data) by implementing the `BatchProcessor` interface. See docs for more details.
138+
To get started with indexing media quickly, you can use the provided `ImageIndex` and `VideoIndexer` classes as shown below. You can optionally create your own indexers (including for text related data) by extending the `BatchProcessor`. See [docs](docs/core/processors.md) for more details.
129139

130140
#### Image Indexing
131141

132142
Index images to enable similarity search. The index is saved as a binary file and managed with a FileEmbeddingStore.
133-
> **Important**: During indexing the MediaStore Id is used to as the id in the `Embedding` which is stored. This can later be used for retrieval.
143+
> **Important**: During indexing the MediaStore Id is used to as the id in the `StoredEmbedding` which is stored. This can later be used for retrieval.
134144
135145

136146
```kotlin
137147
val imageEmbedder = ClipImageEmbedder(context, ResourceId(R.raw.image_encoder_quant_int8))
138-
val imageStore = FileEmbeddingStore(File(context.filesDir, "image_index.bin"), imageEmbedder.embeddingDim, useCache = false) // cache not needed for indexing
148+
val imageStore = FileEmbeddingStore(File(context.filesDir, "image_index.bin"), imageEmbedder.embeddingDim)
139149
val imageIndexer = ImageIndexer(imageEmbedder, context=context, listener = null, store = imageStore) //optionally pass a listener to handle events
140150
val ids = getImageIds() // placeholder function to get MediaStore image ids
141151
imageIndexer.run(ids)
@@ -144,10 +154,11 @@ imageIndexer.run(ids)
144154
#### Video Indexing
145155

146156
Index videos to enable similarity search. The index is saved as a binary file and managed with a FileEmbeddingStore.
157+
> **Important**: During indexing the MediaStore Id is used to as the id in the `StoredEmbedding` which is stored. This can later be used for retrieval.
147158
148159
```kotlin
149160
val imageEmbedder = ClipImageEmbedder(context, ResourceId(R.raw.image_encoder_quant_int8))
150-
val videoStore = FileEmbeddingStore(File(context.filesDir, "video_index.bin"), imageEmbedder.embeddingDim, useCache = false )
161+
val videoStore = FileEmbeddingStore(File(context.filesDir, "video_index.bin"), imageEmbedder.embeddingDim )
151162
val videoIndexer = VideoIndexer(imageEmbedder, context=context, listener = null, store = videoStore, width = ClipConfig.IMAGE_SIZE_X, height = ClipConfig.IMAGE_SIZE_Y)
152163
val ids = getVideoIds() // placeholder function to get MediaStore video ids
153164
videoIndexer.run(ids)
@@ -160,30 +171,46 @@ Below shows how to search using both text queries and an image. The returns resu
160171
#### Text-to-Image Search
161172

162173
```kotlin
163-
val imageStore = FileEmbeddingStore(File(context.filesDir, "image_index.bin"), imageEmbedder.embeddingDim, useCache = false) // cache not needed for indexing
164-
val imageRetriever = FileEmbeddingRetriever(imageStore)
165-
val textEmbedder = ClipTextEmbedder(context, ResourceId(R.raw.text_encoder_quant_int8))
174+
val imageStore = FileEmbeddingStore(File(context.filesDir, "image_index.bin"), imageEmbedder.embeddingDim)
166175
val query = "my search query"
167176
val embedding = textEmbedder.embed(query)
168177
val topK = 20
169178
val similarityThreshold = 0.2f
170-
val results = retriever.query(embedding, topK, similarityThreshold)
179+
val results = imageStore.query(embedding, topK, similarityThreshold) // returns image ids, optionally pass filter ids
171180

172181
```
173182

174183
#### Reverse Image Search
175184

176185
```kotlin
177-
val imageStore = FileEmbeddingStore(File(context.filesDir, "image_index.bin"), imageEmbedder.embeddingDim, useCache = false) // cache not needed for indexing
178-
val imageRetriever = FileEmbeddingRetriever(imageStore)
179-
val imageEmbedder = ClipImageEmbedder(context, ResourceId(R.raw.image_encoder_quant_int8))
186+
val imageStore = FileEmbeddingStore(File(context.filesDir, "image_index.bin"), imageEmbedder.embeddingDim)
180187
val embedding = imageEmbedder.embed(bitmap)
181188
val topK = 20
182189
val similarityThreshold = 0.2f
183-
val results = retriever.query(embedding, topK, similarityThreshold)
190+
val results = imageStore.query(embedding, topK, similarityThreshold)
191+
```
192+
193+
#### ANN Search (HNSW Index)
184194

195+
```kotlin
196+
val annIndex = HNSWIndex(dim=512)
197+
val query = "my search query"
198+
val embedding = textEmbedder.embed(query)
199+
val topK = 5
200+
val results = annIndex.query(embedding, topK) // returns nearest neighbour indices must map to item id
185201
```
186202

203+
### Clustering
204+
205+
Incremental clustering groups embeddings as they are added see [docs](docs/core/clustering.md) for more details.
206+
207+
```kotlin
208+
val imageStore = FileEmbeddingStore(File(context.filesDir, "image_index.bin"), imageEmbedder.embeddingDim)
209+
val itemEmbeds = store.get()
210+
val existingClusters: Map<Long, Cluster> = emptyMap() // optionally pass existing clusters
211+
val clusterer = IncrementalClusterer(existingClusters = existingClusters, defaultThreshold = 0.4f)
212+
val result = clusterer.cluster(itemEmbeds)
213+
```
187214
---
188215

189216
## Design Choices

0 commit comments

Comments
 (0)