grape-image-search 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- grape_image_search-0.1.0/LICENSE +21 -0
- grape_image_search-0.1.0/PKG-INFO +201 -0
- grape_image_search-0.1.0/README.md +165 -0
- grape_image_search-0.1.0/grape/__init__.py +0 -0
- grape_image_search-0.1.0/grape/__main__.py +3 -0
- grape_image_search-0.1.0/grape/cache.py +367 -0
- grape_image_search-0.1.0/grape/cli.py +1146 -0
- grape_image_search-0.1.0/grape/hf_cache.py +80 -0
- grape_image_search-0.1.0/grape/model.py +534 -0
- grape_image_search-0.1.0/grape/search.py +324 -0
- grape_image_search-0.1.0/grape_image_search.egg-info/PKG-INFO +201 -0
- grape_image_search-0.1.0/grape_image_search.egg-info/SOURCES.txt +24 -0
- grape_image_search-0.1.0/grape_image_search.egg-info/dependency_links.txt +1 -0
- grape_image_search-0.1.0/grape_image_search.egg-info/entry_points.txt +2 -0
- grape_image_search-0.1.0/grape_image_search.egg-info/requires.txt +18 -0
- grape_image_search-0.1.0/grape_image_search.egg-info/top_level.txt +1 -0
- grape_image_search-0.1.0/pyproject.toml +87 -0
- grape_image_search-0.1.0/setup.cfg +4 -0
- grape_image_search-0.1.0/tests/test_cache.py +277 -0
- grape_image_search-0.1.0/tests/test_cli.py +1106 -0
- grape_image_search-0.1.0/tests/test_docs.py +35 -0
- grape_image_search-0.1.0/tests/test_lint.py +22 -0
- grape_image_search-0.1.0/tests/test_model.py +144 -0
- grape_image_search-0.1.0/tests/test_model_unit.py +59 -0
- grape_image_search-0.1.0/tests/test_search.py +256 -0
- grape_image_search-0.1.0/tests/test_view.py +118 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mike Graham
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: grape-image-search
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Find images matching keywords using CLIP. Like grep, but for images.
|
|
5
|
+
Author-email: Mike Graham <mikegraham@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Classifier: Development Status :: 4 - Beta
|
|
8
|
+
Classifier: Environment :: Console
|
|
9
|
+
Classifier: Operating System :: OS Independent
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Topic :: Multimedia :: Graphics
|
|
16
|
+
Requires-Python: >=3.10
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: open-clip-torch>=2.24.0
|
|
20
|
+
Requires-Dist: torch>=2.0.0
|
|
21
|
+
Requires-Dist: dask>=2024.5.0
|
|
22
|
+
Requires-Dist: Pillow>=9.0.0
|
|
23
|
+
Requires-Dist: platformdirs>=3.0
|
|
24
|
+
Requires-Dist: tqdm>=4.60
|
|
25
|
+
Requires-Dist: transformers>=4.49.0
|
|
26
|
+
Requires-Dist: sentencepiece>=0.2.0
|
|
27
|
+
Requires-Dist: Jinja2>=3.1
|
|
28
|
+
Requires-Dist: pywebview>=6.1
|
|
29
|
+
Provides-Extra: view
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
32
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
33
|
+
Requires-Dist: ruff>=0.4.0; extra == "dev"
|
|
34
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
35
|
+
Dynamic: license-file
|
|
36
|
+
|
|
37
|
+
# grape
|
|
38
|
+
|
|
39
|
+
Find images matching keywords using [CLIP](https://arxiv.org/abs/2103.00020)
|
|
40
|
+
(Radford et al., 2021). Like grep, but for images.
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
$ grape -R -s -k sunset ~/Pictures
|
|
44
|
+
0.327 ~/Pictures/vacation/beach_golden_hour.jpg
|
|
45
|
+
0.285 ~/Pictures/vacation/pier_evening.jpg
|
|
46
|
+
0.241 ~/Pictures/hiking/mountain_view.jpg
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
<img src="docs/screenshot_view.png" alt="grape --view screenshot" width="600">
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
pip install grape-image-search
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Python 3.10+. Model weights (~1.7 GB for the default) download on first run.
|
|
58
|
+
|
|
59
|
+
For a headless install without the `--view` GUI deps:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
pip install grape-image-search --no-deps
|
|
63
|
+
pip install open-clip-torch torch dask Pillow platformdirs tqdm transformers sentencepiece
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Usage
|
|
67
|
+
|
|
68
|
+
Paths can be files, directories (with `-R`), or `-` to read from stdin.
|
|
69
|
+
At least one of `-k` or `--like` is required.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# text search
|
|
73
|
+
grape -R -k sunset ~/Pictures
|
|
74
|
+
|
|
75
|
+
# find images similar to a reference
|
|
76
|
+
grape -R --like ref.jpg ~/Pictures
|
|
77
|
+
|
|
78
|
+
# combine text + reference, and penalize something
|
|
79
|
+
grape -R -k dog -x cat --like my_dog.jpg ~/Pictures
|
|
80
|
+
|
|
81
|
+
# top 5 above a threshold, with scores
|
|
82
|
+
grape -R -s -n 5 -t 0.25 -k sunset ~/Pictures
|
|
83
|
+
|
|
84
|
+
# browse results in a GUI window
|
|
85
|
+
grape -R -k sunset --view ~/Pictures
|
|
86
|
+
|
|
87
|
+
# aesthetic ranking (skip default templating -- prompts are already full sentences)
|
|
88
|
+
grape -R -n 20 --ensemble-prompts '{}' -k 'beautiful photo' -x 'ugly photo' ~/Pictures
|
|
89
|
+
|
|
90
|
+
# read paths from stdin
|
|
91
|
+
find ~/Pictures -mtime -7 -type f | grape -k selfie -
|
|
92
|
+
|
|
93
|
+
# copy the top 10 cat photos to a folder
|
|
94
|
+
grape -R -print0 -n 10 -k cat ~/Pictures | xargs -0 cp -t ~/cats/
|
|
95
|
+
|
|
96
|
+
# open the best match directly
|
|
97
|
+
grape -R -k 'golden gate bridge' -n 1 ~/Pictures | xargs open
|
|
98
|
+
|
|
99
|
+
# interactive selection with fzf
|
|
100
|
+
grape -R -k dog ~/Pictures | fzf --preview 'chafa {}'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Run `grape --help` for the full flag list.
|
|
104
|
+
|
|
105
|
+
## Worked examples
|
|
106
|
+
|
|
107
|
+
**Per-keyword breakdown** (`-v`) shows how each keyword and `--like`
|
|
108
|
+
reference contributes. The score on the header line is the mean.
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
$ grape -R -v -n 3 --keywords 'playful puppy,golden retriever' ~/Pictures
|
|
112
|
+
0.342 /home/me/Pictures/family/biscuit_park.jpg
|
|
113
|
+
playful puppy: 0.301 golden retriever: 0.383
|
|
114
|
+
0.298 /home/me/Pictures/family/biscuit_couch.jpg
|
|
115
|
+
playful puppy: 0.267 golden retriever: 0.329
|
|
116
|
+
0.274 /home/me/Pictures/family/old_biscuit.jpg
|
|
117
|
+
playful puppy: 0.198 golden retriever: 0.350
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Calibrate, then threshold.** Run with `-s` first to see what scores real
|
|
121
|
+
matches land at, then set `-t` just below the noise floor.
|
|
122
|
+
|
|
123
|
+
```
|
|
124
|
+
$ grape -R -s --keywords sunset ~/Pictures | head -5
|
|
125
|
+
0.312 /home/me/Pictures/travel/santorini_evening.jpg
|
|
126
|
+
0.287 /home/me/Pictures/deck_sunset.jpg
|
|
127
|
+
0.244 /home/me/Pictures/travel/ocean_dusk.jpg
|
|
128
|
+
0.198 /home/me/Pictures/outdoor/golden_leaves.jpg # weak, off-topic
|
|
129
|
+
$ grape -R -s -t 0.24 --keywords sunset ~/Pictures
|
|
130
|
+
0.312 /home/me/Pictures/travel/santorini_evening.jpg
|
|
131
|
+
0.287 /home/me/Pictures/deck_sunset.jpg
|
|
132
|
+
0.244 /home/me/Pictures/travel/ocean_dusk.jpg
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Aesthetic ranking** uses `--exclude` to subtract the mean score of a
|
|
136
|
+
contrast prompt. Scores are smaller here because both sides are competing.
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
$ grape -R -s -n 5 --ensemble-prompts '{}' \
|
|
140
|
+
--keywords 'beautiful photo' --exclude 'ugly photo' ~/travel/
|
|
141
|
+
0.163 /home/me/travel/kyoto_arashiyama.jpg
|
|
142
|
+
0.139 /home/me/travel/iceland_sunset.jpg
|
|
143
|
+
0.127 /home/me/travel/nepal_trek.jpg
|
|
144
|
+
0.109 /home/me/travel/paris_evening.jpg
|
|
145
|
+
0.091 /home/me/travel/tokyo_skyline.jpg
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Scoring
|
|
149
|
+
|
|
150
|
+
Grape ranks images by cosine similarity between CLIP embeddings. Each
|
|
151
|
+
image's score is:
|
|
152
|
+
|
|
153
|
+
mean(similarity to --keywords and --like) - mean(similarity to --exclude)
|
|
154
|
+
|
|
155
|
+
Cosine similarities are **not probabilities**. Meaningful matches typically
|
|
156
|
+
sit in the 0.15-0.35 range; even strong matches rarely exceed 0.35. Use `-s`
|
|
157
|
+
to calibrate before choosing a `-t` threshold. Scores are **not comparable
|
|
158
|
+
across models** -- switch models and the numbers shift.
|
|
159
|
+
|
|
160
|
+
**`--like` matches semantics, not pixels.** Two different photos of dogs
|
|
161
|
+
playing fetch score high; a photo and its crop do too. For actual duplicate
|
|
162
|
+
detection, use a perceptual-hashing tool like
|
|
163
|
+
[czkawka](https://github.com/qarmin/czkawka).
|
|
164
|
+
|
|
165
|
+
## Caching
|
|
166
|
+
|
|
167
|
+
On by default at `~/.cache/grape/embeddings.db`
|
|
168
|
+
(`$XDG_CACHE_HOME/grape/embeddings.db`). Cached:
|
|
169
|
+
|
|
170
|
+
- Image embeddings (the expensive part; ~80 ms per image on CPU)
|
|
171
|
+
- Text embeddings, keyed by prompt
|
|
172
|
+
- Model identity, so repeat runs skip the torch/open_clip import entirely
|
|
173
|
+
- Image-vs-non-image detection results, so videos and docs are skipped on rescan
|
|
174
|
+
|
|
175
|
+
A warm query scores thousands of images in under a second via a single
|
|
176
|
+
matrix multiply. Entries are keyed by absolute path, file stat (size, mtime,
|
|
177
|
+
inode), and model ID, so they auto-invalidate when files change.
|
|
178
|
+
|
|
179
|
+
Use `--no-cache` to disable or `--cache PATH` to relocate.
|
|
180
|
+
|
|
181
|
+
## Models
|
|
182
|
+
|
|
183
|
+
The default is
|
|
184
|
+
[EVA-CLIP's EVA02-L-14](https://arxiv.org/abs/2303.15389) (Sun et al., 2023)
|
|
185
|
+
pretrained as `merged2b_s4b_b131k` -- strong zero-shot accuracy at moderate
|
|
186
|
+
cost. Pick any [OpenCLIP](https://github.com/mlfoundations/open_clip)
|
|
187
|
+
checkpoint with `--model model_name/pretrained_tag`:
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
grape --model ViT-B-32/laion2b_s34b_b79k -R -k sunset ~/Pictures # fast
|
|
191
|
+
grape --model ViT-L-14/laion2b_s32b_b82k -R -k sunset ~/Pictures # strong
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Embeddings are scoped per model; switching re-encodes everything.
|
|
195
|
+
|
|
196
|
+
Keywords are matched with
|
|
197
|
+
[prompt ensembling](https://arxiv.org/abs/2103.00020) (Radford et al., 2021,
|
|
198
|
+
Section 3.1.4 and Appendix A): each keyword expands into several templates
|
|
199
|
+
("a photo of a {}", "a photo of the {}", ...), each is embedded, then the
|
|
200
|
+
embeddings are averaged and renormalized. Improves zero-shot accuracy over
|
|
201
|
+
a single prompt. Override with `--ensemble-prompts`.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# grape
|
|
2
|
+
|
|
3
|
+
Find images matching keywords using [CLIP](https://arxiv.org/abs/2103.00020)
|
|
4
|
+
(Radford et al., 2021). Like grep, but for images.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
$ grape -R -s -k sunset ~/Pictures
|
|
8
|
+
0.327 ~/Pictures/vacation/beach_golden_hour.jpg
|
|
9
|
+
0.285 ~/Pictures/vacation/pier_evening.jpg
|
|
10
|
+
0.241 ~/Pictures/hiking/mountain_view.jpg
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
<img src="docs/screenshot_view.png" alt="grape --view screenshot" width="600">
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
pip install grape-image-search
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Python 3.10+. Model weights (~1.7 GB for the default) download on first run.
|
|
22
|
+
|
|
23
|
+
For a headless install without the `--view` GUI deps:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
pip install grape-image-search --no-deps
|
|
27
|
+
pip install open-clip-torch torch dask Pillow platformdirs tqdm transformers sentencepiece
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Usage
|
|
31
|
+
|
|
32
|
+
Paths can be files, directories (with `-R`), or `-` to read from stdin.
|
|
33
|
+
At least one of `-k` or `--like` is required.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# text search
|
|
37
|
+
grape -R -k sunset ~/Pictures
|
|
38
|
+
|
|
39
|
+
# find images similar to a reference
|
|
40
|
+
grape -R --like ref.jpg ~/Pictures
|
|
41
|
+
|
|
42
|
+
# combine text + reference, and penalize something
|
|
43
|
+
grape -R -k dog -x cat --like my_dog.jpg ~/Pictures
|
|
44
|
+
|
|
45
|
+
# top 5 above a threshold, with scores
|
|
46
|
+
grape -R -s -n 5 -t 0.25 -k sunset ~/Pictures
|
|
47
|
+
|
|
48
|
+
# browse results in a GUI window
|
|
49
|
+
grape -R -k sunset --view ~/Pictures
|
|
50
|
+
|
|
51
|
+
# aesthetic ranking (skip default templating -- prompts are already full sentences)
|
|
52
|
+
grape -R -n 20 --ensemble-prompts '{}' -k 'beautiful photo' -x 'ugly photo' ~/Pictures
|
|
53
|
+
|
|
54
|
+
# read paths from stdin
|
|
55
|
+
find ~/Pictures -mtime -7 -type f | grape -k selfie -
|
|
56
|
+
|
|
57
|
+
# copy the top 10 cat photos to a folder
|
|
58
|
+
grape -R -print0 -n 10 -k cat ~/Pictures | xargs -0 cp -t ~/cats/
|
|
59
|
+
|
|
60
|
+
# open the best match directly
|
|
61
|
+
grape -R -k 'golden gate bridge' -n 1 ~/Pictures | xargs open
|
|
62
|
+
|
|
63
|
+
# interactive selection with fzf
|
|
64
|
+
grape -R -k dog ~/Pictures | fzf --preview 'chafa {}'
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Run `grape --help` for the full flag list.
|
|
68
|
+
|
|
69
|
+
## Worked examples
|
|
70
|
+
|
|
71
|
+
**Per-keyword breakdown** (`-v`) shows how each keyword and `--like`
|
|
72
|
+
reference contributes. The score on the header line is the mean.
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
$ grape -R -v -n 3 --keywords 'playful puppy,golden retriever' ~/Pictures
|
|
76
|
+
0.342 /home/me/Pictures/family/biscuit_park.jpg
|
|
77
|
+
playful puppy: 0.301 golden retriever: 0.383
|
|
78
|
+
0.298 /home/me/Pictures/family/biscuit_couch.jpg
|
|
79
|
+
playful puppy: 0.267 golden retriever: 0.329
|
|
80
|
+
0.274 /home/me/Pictures/family/old_biscuit.jpg
|
|
81
|
+
playful puppy: 0.198 golden retriever: 0.350
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Calibrate, then threshold.** Run with `-s` first to see what scores real
|
|
85
|
+
matches land at, then set `-t` just below the noise floor.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
$ grape -R -s --keywords sunset ~/Pictures | head -5
|
|
89
|
+
0.312 /home/me/Pictures/travel/santorini_evening.jpg
|
|
90
|
+
0.287 /home/me/Pictures/deck_sunset.jpg
|
|
91
|
+
0.244 /home/me/Pictures/travel/ocean_dusk.jpg
|
|
92
|
+
0.198 /home/me/Pictures/outdoor/golden_leaves.jpg # weak, off-topic
|
|
93
|
+
$ grape -R -s -t 0.24 --keywords sunset ~/Pictures
|
|
94
|
+
0.312 /home/me/Pictures/travel/santorini_evening.jpg
|
|
95
|
+
0.287 /home/me/Pictures/deck_sunset.jpg
|
|
96
|
+
0.244 /home/me/Pictures/travel/ocean_dusk.jpg
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
**Aesthetic ranking** uses `--exclude` to subtract the mean score of a
|
|
100
|
+
contrast prompt. Scores are smaller here because both sides are competing.
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
$ grape -R -s -n 5 --ensemble-prompts '{}' \
|
|
104
|
+
--keywords 'beautiful photo' --exclude 'ugly photo' ~/travel/
|
|
105
|
+
0.163 /home/me/travel/kyoto_arashiyama.jpg
|
|
106
|
+
0.139 /home/me/travel/iceland_sunset.jpg
|
|
107
|
+
0.127 /home/me/travel/nepal_trek.jpg
|
|
108
|
+
0.109 /home/me/travel/paris_evening.jpg
|
|
109
|
+
0.091 /home/me/travel/tokyo_skyline.jpg
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Scoring
|
|
113
|
+
|
|
114
|
+
Grape ranks images by cosine similarity between CLIP embeddings. Each
|
|
115
|
+
image's score is:
|
|
116
|
+
|
|
117
|
+
mean(similarity to --keywords and --like) - mean(similarity to --exclude)
|
|
118
|
+
|
|
119
|
+
Cosine similarities are **not probabilities**. Meaningful matches typically
|
|
120
|
+
sit in the 0.15-0.35 range; even strong matches rarely exceed 0.35. Use `-s`
|
|
121
|
+
to calibrate before choosing a `-t` threshold. Scores are **not comparable
|
|
122
|
+
across models** -- switch models and the numbers shift.
|
|
123
|
+
|
|
124
|
+
**`--like` matches semantics, not pixels.** Two different photos of dogs
|
|
125
|
+
playing fetch score high; a photo and its crop do too. For actual duplicate
|
|
126
|
+
detection, use a perceptual-hashing tool like
|
|
127
|
+
[czkawka](https://github.com/qarmin/czkawka).
|
|
128
|
+
|
|
129
|
+
## Caching
|
|
130
|
+
|
|
131
|
+
On by default at `~/.cache/grape/embeddings.db`
|
|
132
|
+
(`$XDG_CACHE_HOME/grape/embeddings.db`). Cached:
|
|
133
|
+
|
|
134
|
+
- Image embeddings (the expensive part; ~80 ms per image on CPU)
|
|
135
|
+
- Text embeddings, keyed by prompt
|
|
136
|
+
- Model identity, so repeat runs skip the torch/open_clip import entirely
|
|
137
|
+
- Image-vs-non-image detection results, so videos and docs are skipped on rescan
|
|
138
|
+
|
|
139
|
+
A warm query scores thousands of images in under a second via a single
|
|
140
|
+
matrix multiply. Entries are keyed by absolute path, file stat (size, mtime,
|
|
141
|
+
inode), and model ID, so they auto-invalidate when files change.
|
|
142
|
+
|
|
143
|
+
Use `--no-cache` to disable or `--cache PATH` to relocate.
|
|
144
|
+
|
|
145
|
+
## Models
|
|
146
|
+
|
|
147
|
+
The default is
|
|
148
|
+
[EVA-CLIP's EVA02-L-14](https://arxiv.org/abs/2303.15389) (Sun et al., 2023)
|
|
149
|
+
pretrained as `merged2b_s4b_b131k` -- strong zero-shot accuracy at moderate
|
|
150
|
+
cost. Pick any [OpenCLIP](https://github.com/mlfoundations/open_clip)
|
|
151
|
+
checkpoint with `--model model_name/pretrained_tag`:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
grape --model ViT-B-32/laion2b_s34b_b79k -R -k sunset ~/Pictures # fast
|
|
155
|
+
grape --model ViT-L-14/laion2b_s32b_b82k -R -k sunset ~/Pictures # strong
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Embeddings are scoped per model; switching re-encodes everything.
|
|
159
|
+
|
|
160
|
+
Keywords are matched with
|
|
161
|
+
[prompt ensembling](https://arxiv.org/abs/2103.00020) (Radford et al., 2021,
|
|
162
|
+
Section 3.1.4 and Appendix A): each keyword expands into several templates
|
|
163
|
+
("a photo of a {}", "a photo of the {}", ...), each is embedded, then the
|
|
164
|
+
embeddings are averaged and renormalized. Improves zero-shot accuracy over
|
|
165
|
+
a single prompt. Override with `--ensemble-prompts`.
|
|
File without changes
|