Calculez facilement les intégrations de clips et créez un système clip retrieval avec elles. 100 millions d'intégrations de texte et d'images peuvent être traitées en 20 heures à l'aide d'un 3080.
De bout en bout, cela permet de construire un système de recherche sémantique simple. Vous souhaitez en savoir plus sur la recherche sémantique en général ? Vous pouvez lire mon article médium sur le sujet.
Voir également laion5B et la recherche sémantique à l'échelle des milliards pour en savoir plus sur la manière d'atteindre cette échelle en milliards d'échantillons.
Si vous croyez en la création d'outils réutilisables pour rendre les données faciles à utiliser pour le ML et que vous souhaitez contribuer, veuillez rejoindre le chat DataToML.
pip installer la récupération de clips
Si vous êtes intéressé à exécuter l'index laion5B, consultez cette doc
ClipClient
permet d'interroger à distance un backend de récupération de clips via python.
Voir ClipClient
- Getting Started Notebook pour un exemple de notebook jupyter.
Lors de l'initialisation, vous pouvez spécifier quelques paramètres :
backend_url
: l'url du backend. (requis)indice_name
: spécifiez le nom de l'index que vous souhaitez utiliser. (requis)aesthetic_score
: le score esthétique évalué par le prédicteur esthétique. La valeur par défaut est 9
.use_mclip
: s'il faut utiliser une version multilingue de CLIP. La valeur par défaut est False
.aesthetic_weight
: le poids de la note esthétique. La valeur par défaut est 0.5
modality
: recherche sur image ou texte dans l'index, l'un des Multimodal.IMAGE
ou Multimodal.TEXT
. La valeur par défaut est Multimodal.IMAGE
.num_images
: le nombre d'images à renvoyer depuis l'API. La valeur par défaut est 40
.deduplicate
: s'il faut dédupliquer le résultat par intégration d'image. La valeur par défaut est vraie.use_safety_model
: s'il faut supprimer les images non sécurisées. La valeur par défaut est vraie.use_violence_detector
: s'il faut supprimer les images avec violence. La valeur par défaut est vraie.Par exemple, pour interroger le backend hébergé pour Laion5B avec les paramètres par défaut :
from clip_retrieval . clip_client import ClipClient , Modality
client = ClipClient ( url = "https://knn.laion.ai/knn-service" , indice_name = "laion5B-L-14" )
Vous pouvez trouver des images sous-titrées similaires au texte que vous fournissez.
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 }
Vous pouvez également trouver des images sous-titrées similaires à l’image que vous fournissez. Les images peuvent être transmises via un chemin local ou une URL.
cat_results = client . query ( image = "cat.jpg" )
dog_results = client . query ( image = "https://example.com/dog.jpg" )
Vous pouvez également trouver des images sous-titrées similaires à l’intégration d’un clip que vous fournissez.
cat_results = client . query ( embedding_input = cat_embedding )
Pour améliorer un ensemble de données existant avec des paires texte/image similaires, vous pouvez interroger un répertoire d'images et combiner les résultats.
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 )
Vous pouvez créer un ensemble de données à l'aide des résultats json enregistrés et de l'outil img2dataset
.
img2dataset " search-results.json "
--input_format= " json "
--output_folder= " knn_search_dataset "
--caption_col= " caption "
Choisissez d’abord un ensemble de données d’URL et de légendes d’images (exemples), puis exécutez :
Vous souhaiterez peut-être exécuter export CUDA_VISIBLE_DEVICES=
pour éviter d'utiliser votre GPU s'il ne dispose pas de suffisamment de VRAM.
wget https://github.com/rom1504/img2dataset/raw/main/tests/test_files/test_1000.parquet
clip-retrieval end2end test_1000.parquet /tmp/my_output
Ensuite, allez sur http://localhost:1234 et profitez de la recherche parmi vos photos
Utilisez --run_back False
si vous ne souhaitez pas exécuter le backend
Récupérez des images dans un example_folder
, par exemple en faisant :
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
Vous pouvez également placer des fichiers texte portant les mêmes noms que les images dans ce dossier, pour obtenir les intégrations de texte.
Ensuite, exécutez clip-retrieval inference --input_dataset image_folder --output_folder embeddings_folder
Le dossier de sortie contiendra :
Cela s’étend à des millions d’échantillons. À 1 400 échantillons/s d'un 3 080, 10 millions d'échantillons peuvent être traités en 2 heures.
clip_inference transforme un ensemble de texte + image en intégrations de clips
"open_clip:ViT-B-32/laion2b_s34b_b79k"
pour utiliser open_clip ou "hf_clip:patrickjohncyh/fashion-clip"
pour utiliser le modèle de clip de visage câlin. DeepSparse est un runtime d'inférence pour l'inférence rapide de modèles clairsemés sur les processeurs. Il existe un backend disponible dans clip-retrieval en l'installant avec pip install deepsparse-nightly[clip]
et en spécifiant un clip_model
avec un "nm:"
préfixé, tel que "nm:neuralmagic/CLIP-ViT-B-32-256x256-DataComp-s34B-b86K-quant-ds"
ou "nm:mgoin/CLIP-ViT-B-32-laion2b_s34b_b79k-ds"
.
Si vous souhaitez avoir plus de contrôle sur la façon dont l'inférence est exécutée, vous pouvez créer et appeler des travailleurs directement à l'aide clip-retrieval inference.worker
Exemple d'utilisation :
clip-retrieval inference.worker
--tasks= " [0] "
--input_dataset= " input/folder/{000000..000100}.tar "
--output_folder= " example/path "
--input_format= " webdataset "
--output_partition_count= " 1 "
Cela invoquera un seul travailleur qui pourra être invité à se concentrer sur un sous-ensemble spécifique du input_dataset
. Ce travailleur traitera séquentiellement les tasks
qui lui seront confiées. Ici, tasks
sont une liste de partition_id
dont ce travailleur sera responsable.
Pour calculer manuellement le nombre de tâches, utilisez la formule suivante : number_samples / wds_number_file_per_input_file
.
L'API est très similaire à clip-retrieval inference
avec quelques modifications mineures :
partition_id
que ce travailleur est responsable du calcul. ( requis )"open_clip:ViT-B-32-quickgelu"
pour utiliser open_clip ou "hf_clip:patrickjohncyh/fashion-clip"
pour utiliser le modèle de clip de visage câlin.Remarque : Le travailleur n'accepte pas les arguments suivants
- write_batch_size Taille du lot d'écriture (par défaut 10**6 )
- distribution_strategy choisit comment distribuer le travail, voir la section distribution pour plus de détails ( séquentiel par défaut)
- wds_number_file_per_input_file estimation du nombre d'échantillons par tar si vous utilisez wds et ne spécifiez pas output_partition_count (par défaut 10000 )
- l'un des arguments SLURM
Exemple de requête hdfs utilisant le format webdataset : `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
Pour l'exécuter sur plusieurs nœuds (et plusieurs GPU), consultez le didacticiel sur docs/distributed_clip_inference.md
L'index de clip prend en entrée la sortie de l'inférence de clip et en fait un index en utilisant autofaiss
clip-retrieval index --embeddings_folder embeddings_folder --index_folder index_folder
--max_index_memory_usage "16G"
permet de configurer la quantité de RAM que l'index consommera. Plus de RAM, meilleur rappel de knn ( 4G
par défaut).--current_memory_available 24G
permet de contrôler la quantité de RAM utilisée pendant le processus de création (par défaut 16G
).--image_subfolder "img_emb"
permet de spécifier un sous-dossier pour les intégrations d'images qui est concaténé à l'option --embeddings_folder
( img_emb
par défaut).--text_subfolder "text_emb"
permet de spécifier un sous-dossier pour les intégrations de texte qui est concaténé à l'option --embeddings_folder
( text_emb
par défaut).--copy_metadata True
permet de choisir de copier ou non les métadonnées à la fin du processus (Default True
).--nb_cores 8
permet de contrôler le nombre de threads (par défaut None
, qui utilisera tous les cœurs).La sortie est un dossier contenant :
Grâce à autofaiss et faiss, cela atteint des centaines de millions d'échantillons en quelques heures.
Vous souhaiterez peut-être choisir soigneusement la quantité de mémoire à utiliser pour votre index afin de maximiser le rappel knn. autofaiss index selection colab peut vous aider avec la commande autofaiss score_index
pour vérifier le rappel de votre index. En général, les indices utilisant plus de mémoire obtiennent un meilleur rappel et sont donc plus proches d'un knn naïf (lent).
Une fois les intégrations calculées, vous souhaiterez peut-être filtrer les données par une requête spécifique. Pour cela, vous pouvez exécuter clip-retrieval filter --query "cat" --output_folder "cat/" --indice_folder "indice_folder"
Il copiera les 100 meilleures images pour cette requête dans le dossier de sortie. L'utilisation de --num_results
ou --threshold
peut être utile pour affiner le filtre
Grâce à l'index knn rapide, cela peut s'exécuter en temps réel (<10 ms) pour les grandes valeurs K (100 000) et en quelques minutes pour les très grandes valeurs K.
Ces scripts fonctionnent pour de petits ensembles de données. Pour les plus grands, veuillez consulter [notebook/simple_filter.ipynb].
Clip back est un simple backend de service knn. Si vous utilisez à la fois le mappage de mémoire hdf5 et faiss, il utilise uniquement la mémoire utilisée par le clip, qui est de 4 Go.
Exécuter (output_folder est la sortie de l'index du clip)
echo ' {"example_index": "output_folder"} ' > indices_paths.json
clip-retrieval back --port 1234 --indices-paths indices_paths.json
Possibilités :
--use_jit True
utilise jit pour le modèle de clip--clip_model "ViT-B/32"
permet de choisir le modèle de clip à utiliser. Préfixez "open_clip:"
pour utiliser un modèle open_clip.--enable_mclip_option True
charge le modèle mclip, permettant d'effectuer une recherche dans n'importe quelle langue.--columns_to_return='["url", "image_path", "caption", "NSFW"]
vous permet de spécifier quelles colonnes doivent être récupérées à partir des métadonnées et renvoyées par le backend. Il est utile d'en spécifier moins en cas de mise en cache hdf5 pour accélérer les requêtes.--enable_faiss_memory_mapping=True
peut être passée pour utiliser un index avec un mappage mémoire. Cela réduit l'utilisation de la mémoire à zéro.--enable_hdf5 True
peut être transmise pour activer la mise en cache hdf5 pour les métadonnées. La mise en cache HDF5 permet d'utiliser les métadonnées avec presque aucune utilisation de mémoire.--use_arrow True
permet d'utiliser la flèche au lieu de hdf5. Doit être utilisé avec clip_back_prepro pour de très grands ensembles de données (milliards)--reorder_metadata_by_ivf_index True
profite de la propriété de localité des données des résultats d'un index ivf knn : elle ordonne la collecte des métadonnées dans l'ordre des clusters FIV. Cela permet d'obtenir une récupération des métadonnées beaucoup plus rapide, car les lectures accèdent alors à quelques parties principalement séquentielles des métadonnées au lieu de nombreuses parties non séquentielles. En pratique, cela signifie être capable de récupérer 1 million d'éléments en 1 seconde alors que seuls 1 000 éléments peuvent être récupérés en 1 seconde sans cette méthode. Cela ordonnera les métadonnées en utilisant le premier index d'image.--provide_safety_model True
téléchargera et chargera automatiquement un modèle de sécurité. Vous devez pip install autokeras
pour que cela fonctionne.--provide_violence_detector True
chargera un détecteur de violence, du papier--provide_aesthetic_embeddings True
chargera les intégrations esthétiques et permettra aux utilisateurs de déplacer la requête vers un point plus agréable de l'espace du clip.Ces options peuvent également être fournies dans le fichier de configuration pour avoir des options différentes pour chaque index. Exemple:
{
"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 "
}
}
La mise en cache hdf5 ou arrow est une bonne idée à utiliser si :
À ce stade, vous disposez d'un simple serveur Flask fonctionnant sur le port 1234 et qui peut répondre à ces requêtes :
/indices-list
-> renvoie une liste d'indices/knn-service
qui prend en entrée : {
"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 et image_url s'excluent mutuellement et renvoient :
[
{
"image" : "base 64 of an image" ,
"text" : "some result text" ,
"id" : 543
} ,
{
"image" : "base 64 of an image" ,
"text" : "some result text" ,
"id" : 782
}
]
Chaque objet peut également contenir un champ url si les métadonnées le fournissent.
L'identifiant est la position de l'élément dans l'index. Il peut être utilisé pour interroger des métadonnées avec le point de terminaison /metadata :
{
"indice_name" : "example_index" ,
"ids" : [ 543 , 782 ]
}
qui renvoie :
{
"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
}
L'argument num_result_ids
de /knn-service
et /metadata
peut être utilisé ensemble pour effectuer de grandes requêtes knn, puis récupérer les métadonnées uniquement en cas de besoin. Cela est logique car la recherche knn peut être très efficace grâce à la forte localité de référence de l'index de FIV knn, ce qui permet de faire rapidement knn avec un grand K, alors que l'implémentation actuelle des métadonnées sur disque (hdf5) n'a pas cela. propriété et ne peut donc pas gérer la récupération rapide d’une grande quantité d’éléments aléatoires. En particulier, cela peut être utilisé pour implémenter un défilement infini dans un frontal.
Par défaut, le backend exposera également un front-end. Ce frontal atteindra par défaut ce backend, mais vous devrez peut-être spécifier si cela se produit via http ou https, dans ce cas, utilisez l'option --default_backend
pour spécifier l'URL du backend. --url_column
permet de spécifier le nom de l'url de la colonne pour le front
Ce backend a une latence de 50 ms si vous utilisez des index et des métadonnées mappés en mémoire. Le débit est d’environ 20 requêtes/s. Pour un débit élevé, l'utilisation d'un serveur grpc est requise ainsi que d'un GPU pour une inférence rapide de clips. La désactivation des options de mappage de mémoire peut également accélérer les requêtes, au prix d'une utilisation élevée de la RAM.
Ce backend expose également un point de terminaison prometheus /metrics
ainsi qu'un résumé lisible par l'homme à l'adresse /metrics-summary
. Cela peut (éventuellement) être utilisé pour configurer un tableau de bord grafana pour la surveillance :
On peut voir sur ce tableau de bord que la partie la plus lente de tout appel consiste à récupérer l'image par son URL en cas de recherche d'URL d'image, ce qui prend jusqu'à 300 ms. Pour les requêtes texte ou les requêtes images, la latence est d'environ 50 ms. Voici un exemple de résultat dans le résumé des métriques :
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 est une interface utilisateur simple qui se connecte au clip back et affiche les résultats. Vous pouvez l'utiliser sur l'interface utilisateur de récupération de clips
Ou vous pouvez l'exécuter vous-même avec :
npm install -g clip-retrieval-front
clip-retrieval-front 3005
Vous pouvez également l'exécuter avec clip-retrieval front
ou verso à partir du package python.
Pour le développer, allez au front et exécutez npm install
puis npm start
.
Soit localement, soit dans gitpod ( export PIP_USER=false
ici)
Configurez un virtualenv :
python3 -m venv .env
source .env/bin/activate
pip install -e .
pour faire des tests :
pip install -r requirements-test.txt
alors
make lint
make test
Vous pouvez utiliser make black
pour reformater le code
python -m pytest -x -s -v tests -k "test_runner"
pour exécuter un test spécifique
Si vous souhaitez utiliser le front via le backend ou le frontend python, exécutez
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}}
}