Berechnen Sie ganz einfach Clip-Einbettungen und bauen Sie damit ein clip retrieval auf. 100 Millionen Text- und Bildeinbettungen können mit einem 3080 in 20 Stunden verarbeitet werden.
Dies ermöglicht durchgängig den Aufbau eines einfachen semantischen Suchsystems. Möchten Sie mehr über die semantische Suche im Allgemeinen erfahren? Sie können meinen mittleren Beitrag zum Thema lesen.
Sehen Sie sich auch laion5B und semantische Suche im Milliardenmaßstab an, um mehr darüber zu erfahren, wie Sie diesen Maßstab auf Milliarden von Stichproben übertragen können.
Wenn Sie daran glauben, wiederverwendbare Tools zu entwickeln, um Daten für ML einfach nutzbar zu machen, und einen Beitrag leisten möchten, nehmen Sie bitte am DataToML-Chat teil.
pip install Clip-Retrieval
Wenn Sie daran interessiert sind, den laion5B-Index auszuführen, sehen Sie sich dieses Dokument an
ClipClient
ermöglicht die Fernabfrage eines Clip-Retrieval-Backends über Python.
Ein Beispiel für ein Jupyter-Notebook finden Sie unter ClipClient
– Getting Started Notebook.
Während der Initialisierung können Sie einige Parameter angeben:
backend_url
: die URL des Backends. (erforderlich)indice_name
: Geben Sie den Namen des Index an, den Sie verwenden möchten. (erforderlich)aesthetic_score
: der ästhetische Wert, der vom ästhetischen Prädiktor bewertet wurde. Der Standardwert ist 9
.use_mclip
: ob eine mehrsprachige Version von CLIP verwendet werden soll. Der Standardwert ist False
.aesthetic_weight
: das Gewicht der ästhetischen Bewertung. Der Standardwert ist 0.5
modality
: Suche nach Bild oder Text im Index, entweder Multimodal.IMAGE
oder Multimodal.TEXT
. Der Standardwert ist Multimodal.IMAGE
.num_images
: Die Anzahl der Bilder, die von der API zurückgegeben werden sollen. Der Standardwert ist 40
.deduplicate
: Ob das Ergebnis durch Bilderinbettung dedupliziert werden soll. Der Standardwert ist wahr.use_safety_model
: Ob unsichere Bilder entfernt werden sollen. Der Standardwert ist wahr.use_violence_detector
: Ob Bilder mit Gewalt entfernt werden sollen. Der Standardwert ist wahr.Um beispielsweise das gehostete Backend nach Laion5B mit den Standardparametern abzufragen:
from clip_retrieval . clip_client import ClipClient , Modality
client = ClipClient ( url = "https://knn.laion.ai/knn-service" , indice_name = "laion5B-L-14" )
Sie können Bilder mit Untertiteln finden, die dem von Ihnen bereitgestellten Text ähneln.
results = client . query ( text = "an image of a cat" )
results [ 0 ]
> { 'url' : 'https://example.com/kitten.jpg' , 'caption' : 'an image of a kitten' , 'id' : 14 , 'similarity' : 0.2367108941078186 }
Sie können auch Bilder mit Untertiteln finden, die dem von Ihnen bereitgestellten Bild ähneln. Bilder können über einen lokalen Pfad oder eine URL übergeben werden.
cat_results = client . query ( image = "cat.jpg" )
dog_results = client . query ( image = "https://example.com/dog.jpg" )
Sie können auch mit Untertiteln versehene Bilder finden, die einer von Ihnen bereitgestellten Clip-Einbettung ähneln.
cat_results = client . query ( embedding_input = cat_embedding )
Um einen vorhandenen Datensatz mit ähnlichen Text-/Bildpaaren zu erweitern, können Sie ein Bildverzeichnis abfragen und die Ergebnisse kombinieren.
all_results = [ result for result in [ client . query ( image = image ) for image in os . listdir ( "my-images" )]]
with open ( "search-results.json" , "w" ) as f :
json . dump ( all_results , f )
Sie können einen Datensatz mit den gespeicherten JSON-Ergebnissen und dem Tool img2dataset
erstellen.
img2dataset " search-results.json "
--input_format= " json "
--output_folder= " knn_search_dataset "
--caption_col= " caption "
Wählen Sie zunächst einen Datensatz mit Bild-URLs und Bildunterschriften (Beispiele) aus und führen Sie dann Folgendes aus:
Möglicherweise möchten Sie export CUDA_VISIBLE_DEVICES=
ausführen, um die Verwendung Ihrer GPU zu vermeiden, wenn diese nicht über genügend VRAM verfügt.
wget https://github.com/rom1504/img2dataset/raw/main/tests/test_files/test_1000.parquet
clip-retrieval end2end test_1000.parquet /tmp/my_output
Gehen Sie dann zu http://localhost:1234 und genießen Sie die Suche in Ihren Bildern
Verwenden Sie --run_back False
wenn Sie das Backend nicht ausführen möchten
Holen Sie sich einige Bilder in einen example_folder
, indem Sie beispielsweise Folgendes tun:
pip install img2dataset
echo 'https://placekitten.com/200/305' >> myimglist.txt
echo 'https://placekitten.com/200/304' >> myimglist.txt
echo 'https://placekitten.com/200/303' >> myimglist.txt
img2dataset --url_list=myimglist.txt --output_folder=image_folder --thread_count=64 --image_size=256
Sie können auch Textdateien mit denselben Namen wie die Bilder in diesem Ordner ablegen, um die Texteinbettungen zu erhalten.
Führen Sie dann clip-retrieval inference --input_dataset image_folder --output_folder embeddings_folder
aus
Der Ausgabeordner enthält:
Dies lässt sich auf Millionen von Proben skalieren. Bei 1400 Samples/s eines 3080 können 10 Millionen Samples in 2 Stunden verarbeitet werden.
clip_inference wandelt eine Reihe von Text und Bildern in Clip-Einbettungen um
"open_clip:ViT-B-32/laion2b_s34b_b79k"
an, um den open_clip zu verwenden, oder als "hf_clip:patrickjohncyh/fashion-clip"
um das Hugging-Face-Clip-Modell zu verwenden. DeepSparse ist eine Inferenzlaufzeit für die schnelle Inferenz von Sparse-Modellen auf CPUs. Innerhalb von Clip-Retrieval ist ein Backend verfügbar, indem Sie es mit pip install deepsparse-nightly[clip]
installieren und ein clip_model
mit einem vorangestellten "nm:"
angeben, z. B. "nm:neuralmagic/CLIP-ViT-B-32-256x256-DataComp-s34B-b86K-quant-ds"
oder "nm:mgoin/CLIP-ViT-B-32-laion2b_s34b_b79k-ds"
.
Wenn Sie mehr Kontrolle darüber haben möchten, wie die Inferenz ausgeführt wird, können Sie Worker direkt mit clip-retrieval inference.worker
erstellen und aufrufen
Beispielverwendung:
clip-retrieval inference.worker
--tasks= " [0] "
--input_dataset= " input/folder/{000000..000100}.tar "
--output_folder= " example/path "
--input_format= " webdataset "
--output_partition_count= " 1 "
Dadurch wird ein einzelner Worker aufgerufen, der angewiesen werden kann, sich auf eine bestimmte Teilmenge des input_dataset
zu konzentrieren. Dieser Worker verarbeitet die ihm übergebenen tasks
nacheinander. Hier handelt es sich tasks
um eine Liste der partition_id
, für die dieser Worker verantwortlich sein wird.
Um die Anzahl der Aufgaben manuell zu berechnen, verwenden Sie die folgende Formel: number_samples / wds_number_file_per_input_file
.
Die API ist der clip-retrieval inference
mit einigen geringfügigen Änderungen sehr ähnlich:
partition_id
darstellen, für deren Berechnung dieser Worker verantwortlich ist. ( erforderlich )"open_clip:ViT-B-32-quickgelu"
an, um den open_clip zu verwenden, oder als "hf_clip:patrickjohncyh/fashion-clip"
um das Hugging-Face-Clip-Modell zu verwenden.Hinweis : Der Worker akzeptiert die folgenden Argumente nicht
- write_batch_size Batchgröße schreiben (Standard 10**6 )
- distribution_strategy Wählen Sie aus, wie der Job verteilt werden soll. Einzelheiten finden Sie im Abschnitt „Verteilung“ (Standard sequentiell ).
- wds_number_file_per_input_file Schätzung der Anzahl der Samples pro Tar, wenn wds verwendet wird und kein Output_partition_count angegeben wird (Standard 10000 )
- eines der SLURM-Argumente
Beispiel einer HDFS-Abfrage im Webdataset-Format: `clip_inference --input_dataset "pipe:hdfs dfs -cat /myfolder/webdataset/{00000..00010}.tar" --output_folder "hdfs://myfolder/embeddings" --input_format webdataset
`clip_inference --input_dataset "pipe:aws s3 cp --quiet s3://myfolder/webdataset/{00000..00010}.tar -" --output_folder "s3://myfolder/embeddings" --input_format webdataset
Um dies auf mehreren Knoten (und mehreren GPUs) auszuführen, lesen Sie das Tutorial unter docs/distributed_clip_inference.md
Der Clip-Index verwendet als Eingabe die Ausgabe der Clip-Inferenz und erstellt daraus mithilfe von Autofaiss einen Index
clip-retrieval index --embeddings_folder embeddings_folder --index_folder index_folder
--max_index_memory_usage "16G"
können Sie die Menge an RAM konfigurieren, die der Index verbraucht. Mehr RAM, besserer KnN-Recall (Standard 4G
).--current_memory_available 24G
ermöglicht die Steuerung, wie viel RAM während des Erstellungsprozesses verwendet wird (Standard 16G
).--image_subfolder "img_emb"
ermöglicht die Angabe eines Unterordners für die Bildeinbettungen, der mit der Option --embeddings_folder
(Standard img_emb
) verkettet wird.--text_subfolder "text_emb"
ermöglicht die Angabe eines Unterordners für die Texteinbettungen, der mit der Option --embeddings_folder
(Standard text_emb
) verkettet wird.--copy_metadata True
ermöglicht die Auswahl, ob Metadaten am Ende des Prozesses kopiert werden sollen oder nicht (Standard: True
).--nb_cores 8
ermöglicht die Steuerung der Anzahl der Threads (Standard: None
, wodurch alle Kerne verwendet werden).Die Ausgabe ist ein Ordner mit:
Dank Autofaiss und Faiss lässt sich dies in wenigen Stunden auf Hunderte Millionen Proben skalieren.
Möglicherweise möchten Sie sorgfältig auswählen, wie viel Speicher Sie für Ihren Index verwenden möchten, um den KnN-Rückruf zu maximieren. Autofaiss Index Selection Colab kann zusammen mit dem Befehl autofaiss score_index
dabei helfen, den Abruf Ihres Indexes zu überprüfen. Im Allgemeinen erzielen Indizes, die mehr Speicher nutzen, eine bessere Erinnerung und liegen daher näher an einem naiven (langsamen) KnN
Sobald die Einbettungen berechnet sind, möchten Sie die Daten möglicherweise durch eine bestimmte Abfrage herausfiltern. Dazu können Sie clip-retrieval filter --query "cat" --output_folder "cat/" --indice_folder "indice_folder"
ausführen. Dadurch werden die 100 besten Bilder für diese Abfrage in den Ausgabeordner kopiert. Die Verwendung von --num_results
oder --threshold
kann hilfreich sein, um den Filter zu verfeinern
Dank des schnellen KnN-Index kann dies bei großen K-Werten (100.000) in Echtzeit (<10 ms) und bei sehr großen K-Werten in Minuten erfolgen.
Dieses Skript funktioniert für kleine Datensätze. Für größere Filter schauen Sie bitte unter [notebook/simple_filter.ipynb] nach.
Clip Back ist ein einfaches KnN-Service-Backend. Wenn Sie sowohl HDF5- als auch Faiss-Speicherzuordnung verwenden, wird nur der von Clip verwendete Speicher verwendet, der 4 GB beträgt.
Ausführen (Ausgabeordner ist die Ausgabe des Clip-Index)
echo ' {"example_index": "output_folder"} ' > indices_paths.json
clip-retrieval back --port 1234 --indices-paths indices_paths.json
Optionen:
--use_jit True
verwendet JIT für das Clip-Modell--clip_model "ViT-B/32"
ermöglicht die Auswahl des zu verwendenden Clip-Modells. Stellen Sie "open_clip:"
voran, um ein open_clip-Modell zu verwenden.--enable_mclip_option True
lädt das mclip-Modell und ermöglicht so die Suche in jeder Sprache.--columns_to_return='["url", "image_path", "caption", "NSFW"]
ermöglicht Ihnen festzulegen, welche Spalten aus den Metadaten abgerufen und vom Backend zurückgegeben werden sollen. Bei HDF5-Caching ist es sinnvoll, weniger anzugeben, um die Abfragen zu beschleunigen.--enable_faiss_memory_mapping=True
-Option kann übergeben werden, um einen Index mit Speicherzuordnung zu verwenden. Dadurch wird die Speichernutzung auf Null reduziert.--enable_hdf5 True
kann übergeben werden, um das HDF5-Caching für die Metadaten zu aktivieren. HDF5-Caching ermöglicht die Nutzung der Metadaten nahezu ohne Speicherverbrauch.--use_arrow True
ermöglicht die Verwendung von Pfeil anstelle von HDF5. Sollte zusammen mit clip_back_prepro für sehr große Datensätze (Milliarden) verwendet werden.--reorder_metadata_by_ivf_index True
nutzt die Datenlokalitätseigenschaft der Ergebnisse eines knn-IVF-Indizes: Sie ordnet die Metadatensammlung in der Reihenfolge der IVF-Cluster. Dies ermöglicht einen viel schnelleren Metadatenabruf, da die Lesevorgänge dann auf einige, meist sequentielle Teile der Metadaten statt auf viele nicht sequentielle Teile zugreifen. In der Praxis bedeutet das, dass 1 Million Artikel in 1 Sekunde abgerufen werden können, während ohne diese Methode nur 1000 Artikel in 1 Sekunde abgerufen werden können. Dadurch werden die Metadaten anhand des ersten Bildindexes sortiert.--provide_safety_model True
lädt automatisch ein Sicherheitsmodell herunter und lädt es. Damit dies funktioniert, müssen Sie die optionale pip install autokeras
.--provide_violence_detector True
lädt einen Gewaltdetektor, Papier--provide_aesthetic_embeddings True
lädt die ästhetischen Einbettungen und ermöglicht Benutzern, die Abfrage an einen schöneren Punkt des Clip-Bereichs zu verschiebenDiese Optionen können auch in der Konfigurationsdatei bereitgestellt werden, um für jeden Index unterschiedliche Optionen zu haben. Beispiel:
{
"laion5B" : {
"indice_folder" : " /mnt/laion5B/prepared_data " ,
"provide_safety_model" : true ,
"enable_faiss_memory_mapping" : true ,
"use_arrow" : true ,
"enable_hdf5" : false ,
"reorder_metadata_by_ivf_index" : false ,
"columns_to_return" : [ " url " , " caption " ],
"clip_model" : " ViT-L/14 " ,
"enable_mclip_option" : false
},
"laion_400m" : {
"indice_folder" : " /mnt/laion400M/index100 " ,
"provide_safety_model" : true ,
"enable_faiss_memory_mapping" : true ,
"enable_hdf5" : true ,
"use_arrow" : false ,
"reorder_metadata_by_ivf_index" : true ,
"enable_mclip_option" : true ,
"clip_model" : " ViT-B/32 "
}
}
HDF5- oder Arrow-Caching ist eine gute Idee, wenn:
Zu diesem Zeitpunkt verfügen Sie über einen einfachen Flask-Server, der auf Port 1234 läuft und die folgenden Fragen beantworten kann:
/indices-list
-> gibt eine Liste von Indizes zurück/knn-service
der als Eingabe Folgendes akzeptiert: {
"text" : "a text query" ,
"image" : "a base64 image" ,
"image_url" : "http://some-url.com/a.jpg" ,
"modality" : "image" , // image or text index to use
"num_images" : 4 , // number of output images
"indice_name" : "example_index" ,
"num_result_ids" : 4 // optional, if specified fetch this number of results in total but only num_images with metadata
}
text, image und image_url schließen sich gegenseitig aus und geben Folgendes zurück:
[
{
"image" : "base 64 of an image" ,
"text" : "some result text" ,
"id" : 543
} ,
{
"image" : "base 64 of an image" ,
"text" : "some result text" ,
"id" : 782
}
]
Jedes Objekt kann auch ein URL-Feld enthalten, wenn die Metadaten es bereitstellen.
Die ID ist die Position des Elements im Index. Es kann zum Abfragen von Metadaten mit dem Endpunkt /metadata verwendet werden:
{
"indice_name" : "example_index" ,
"ids" : [ 543 , 782 ]
}
was zurückgibt:
{
"image" : "base 64 of an image" ,
"text" : "some result text"
// any other key available in the metadata and specified in columns_to_return cli option
}
Das Argument num_result_ids
von /knn-service
und /metadata
kann zusammen verwendet werden, um große knn-Abfragen durchzuführen und die Metadaten dann nur bei Bedarf abzurufen. Dies ist sinnvoll, da die KnN-Suche dank der starken Referenzlokalität des Knn-IVF-Index sehr effizient sein kann, wodurch Knn mit einem großen K schnell durchgeführt werden kann, während die aktuelle On-Disk-Implementierung von Metadaten (hdf5) dies nicht bietet Eigenschaft und kann daher nicht mit dem schnellen Abrufen einer großen Menge zufälliger Elemente umgehen. Insbesondere kann dies verwendet werden, um unendliches Scrollen in einem Frontend zu implementieren.
Standardmäßig stellt das Backend auch ein Frontend bereit. Dieses Frontend greift standardmäßig auf dieses Backend zu. Möglicherweise müssen Sie jedoch angeben, ob dies über http oder https geschieht. Verwenden Sie in diesem Fall die Option --default_backend
um die Backend-URL anzugeben. --url_column
ermöglicht die Angabe des Namens der Spalten-URL für die Vorderseite
Dieses Backend hat eine Latenz von 50 ms, wenn speicherzugeordnete Indizes und Metadaten verwendet werden. Der Durchsatz beträgt etwa 20 Abfragen/s. Für einen hohen Durchsatz ist die Verwendung eines GRPC-Servers sowie einer GPU für schnelle Clip-Inferenz erforderlich. Durch das Deaktivieren von Speicherzuordnungsoptionen können Anfragen ebenfalls beschleunigt werden, allerdings auf Kosten einer hohen RAM-Auslastung.
Dieses Backend stellt außerdem einen prometheus /metrics
Endpunkt sowie eine für Menschen lesbare Zusammenfassung unter /metrics-summary
bereit. Dies kann (optional) verwendet werden, um ein Grafana-Dashboard zur Überwachung einzurichten:
Auf diesem Dashboard ist zu sehen, dass der langsamste Teil eines Anrufs im Falle einer Bild-URL-Suche darin besteht, das Bild über seine URL abzurufen, was bis zu 300 ms dauert. Bei Textabfragen oder Bildabfragen beträgt die Latenz etwa 50 ms. Hier ist ein Beispiel für die Ausgabe in der Metrikzusammenfassung:
Among 20.0 calls to the knn end point with an average latency of 0.1889s per request, the step costs are (in order):
name description calls average proportion
0 download_time Time spent downloading an url 6 0.3215s 170.2%
1 metadata_get_time Time spent retrieving metadata 20 0.0415s 21.9%
2 knn_index_time Time spent doing a knn on the index 20 0.0267s 14.1%
3 image_clip_inference_time Time spent doing a image clip inference 6 0.0206s 10.9%
4 text_clip_inference_time Time spent doing a text clip inference 14 0.0186s 9.8%
5 image_prepro_time Time spent doing the image preprocessing 6 0.0097s 5.2%
6 text_prepro_time Time spent doing the text preprocessing 14 0.0020s 1.0%
Clip Front ist eine einfache Benutzeroberfläche, die eine Verbindung zum Clip Back herstellt und die Ergebnisse anzeigt. Sie können es in der Clip-Retrieval-Benutzeroberfläche verwenden
Oder Sie können es selbst ausführen mit:
npm install -g clip-retrieval-front
clip-retrieval-front 3005
Sie können es auch mit clip-retrieval front
oder hinten aus dem Python-Paket ausführen.
Gehen Sie zur Entwicklung nach vorne und führen Sie npm install
und dann npm start
.
Entweder lokal oder in Gitpod ( export PIP_USER=false
)
Richten Sie eine virtuelle Umgebung ein:
python3 -m venv .env
source .env/bin/activate
pip install -e .
um Tests durchzuführen:
pip install -r requirements-test.txt
Dann
make lint
make test
Sie können make black
verwenden, um den Code neu zu formatieren
python -m pytest -x -s -v tests -k "test_runner"
um einen bestimmten Test auszuführen
Wenn Sie die Front über das Python-Backend oder -Frontend verwenden möchten, führen Sie Folgendes aus
cd front
npm install
npm run build
cd ..
pip install -e .
@misc{beaumont-2022-clip-retrieval,
author = {Romain Beaumont},
title = { clip retrieval : Easily compute clip embeddings and build a clip retrieval system with them},
year = {2022},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {url{https://github.com/rom1504/clip-retrieval}}
}