Implementieren der Bildähnlichkeitssuche in Elasticsearch

blog-thumb-website-search.png

Finden Sie heraus, wie Sie die Bildähnlichkeitssuche in Elastic mit nur wenigen Schritten implementieren können. Zunächst richten Sie die Anwendungsumgebung ein, dann importieren Sie das NLP-Modell und zuletzt schließen Sie die Generierung von Einbettungen für Ihren Bilderdatensatz ab.

Hier finden Sie eine Übersicht über die Bildähnlichkeitssuche mit Elastic >> 

Einrichten der Umgebung

Zunächst müssen Sie die Umgebung für Ihre Anwendung einrichten. Allgemeine Anforderungen:

  • Git
  • Python 3.9
  • Docker
  • Hunderte von Bildern

Es ist wichtig, Hunderte von Bildern zu verwenden, um optimale Ergebnisse zu erhalten.

Öffnen Sie den Arbeitsordner und checken Sie den erstellten Repository-Code aus. Navigieren Sie anschließend zum Repository-Ordner.

$ git clone https://github.com/radoondas/flask-elastic-image-search.git
$ cd flask-elastic-image-search

Sie werden Python verwenden, um den Code auszuführen. Daher müssen Sie sicherstellen, dass alle Anforderungen erfüllt sind und die Umgebung bereit ist. Erstellen Sie jetzt die virtuelle Umgebung und installieren Sie sämtliche Abhängigkeiten.

$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install -r requirements.txt

Elasticsearch-Cluster und Einbettungsmodell

Melden Sie sich bei Ihrem Konto an, um ein Elasticsearch-Cluster hochzufahren. Richten Sie ein kleines Cluster ein mit: 

  • einem HEISSEN Knoten mit 2 GB Arbeitsspeicher
  • einem ML-Knoten (Machine Learning) mit 4 GB Arbeitsspeicher (Die Größe dieses Knotens ist wichtig, da das NLP-Modell, das Sie nach Elasticsearch importieren werden, etwa 1,5 GB Arbeitsspeicher verbraucht.)

Sobald Ihr Deployment bereit ist, öffnen Sie Kibana und überprüfen Sie die Kapazität Ihrer Machine-Learning-Knoten. In dieser Ansicht wird ein Machine-Learning-Knoten angezeigt. Bisher wurde noch kein Modell geladen.

Laden Sie das CLIP-Einbettungsmodell von OpenAI mit der Eland-Bibliothek hoch. Eland ist ein Python-Elasticsearch-Client, mit dem Sie Daten in Elasticsearch erkunden und analysieren können und der Texte sowie Bilder verarbeiten kann. Mit diesem Modell werden Sie Einbettungen aus den Texteingaben generieren und nach übereinstimmenden Bildern suchen. Weitere Details finden Sie in der Dokumentation zur Eland-Bibliothek.

Für den nächsten Schritt benötigen Sie den Elasticsearch-Endpoint. Sie finden diesen Endpoint in der Elasticsearch-Cloud-Konsole im Abschnitt mit den Deployment-Details.

Notieren Sie sich die Endpoint-URL und führen Sie den folgenden Befehl im Stammverzeichnis des Repositorys aus. Der Eland-Client verbindet sich mit dem Elasticsearch-Cluster und lädt das Modell auf den Machine-Learning-Knoten hoch. Sie geben Ihre tatsächliche Cluster-URL mit dem Parameter „–url“ an. Das folgende Beispiel verwendet also  „image-search.es.europe-west1.gcp.cloud.es.io“ als Cluster-URL.

--url https://elastic:<password>@image-search.es.europe-west1.gcp.cloud.es.io:443

Geben Sie den Importbefehl für Eland ein.

$ eland_import_hub_model --url https://elastic:<password>@<URL>:443 \
  --hub-model-id sentence-transformers/clip-ViT-B-32-multilingual-v1 \
  --task-type text_embedding --ca-certs app/conf/ess-cloud.cer \
  --start

Die Ausgabe sollte ungefähr so aussehen:

2022-12-12 13:40:52,308 INFO : Establishing connection to Elasticsearch
2022-12-12 13:40:52,327 INFO : Connected to cluster named 'image-search-8.6.1' (version: 8.5.3)
2022-12-12 13:40:52,328 INFO : Loading HuggingFace transformer tokenizer and model 'sentence-transformers/clip-ViT-B-32-multilingual-v1'
2022-12-12 13:41:03,032 INFO : Creating model with id 'sentence-transformers__clip-vit-b-32-multilingual-v1'
2022-12-12 13:41:03,050 INFO : Uploading model definition
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 129/129 [00:42<00:00,  3.01 parts/s]
2022-12-12 13:41:45,902 INFO : Uploading model vocabulary
2022-12-12 13:41:46,120 INFO : Starting model deployment
2022-12-12 13:41:52,825 INFO : Model successfully imported with id 'sentence-transformers__clip-vit-b-32-multilingual-v1'

Der Upload kann je nach Verbindung einige Minuten dauern. Sehen Sie sich anschließend die Liste der trainierten Knoten auf der Machine-Learning-Seite in Kibana an: Menu -> Analytics -> Machine Learning -> Model management -> Trained models. Vergewissern Sie sich, dass das NLP-CLIP-Modell mit dem Status „started“ angezeigt wird.

Falls die Nachricht „ML job and trained model synchronization required“ (Synchronisierung von ML-Job und trainiertem Modell erforderlich) angezeigt wird, klicken Sie auf den Link, um die Modelle zu synchronisieren.

Erstellen von Bildeinbettungen

Nachdem Sie den Elasticsearch-Cluster eingerichtet und das Einbettungsmodell importiert haben, müssen Sie Ihre Bilddaten vektorisieren und Bildeinbettungen für sämtliche Bilder in Ihrem Datensatz erstellen.

Sie können die Bildeinbettungen mit einem einfachen Python-Skript erstellen. Das Skript finden Sie hier: create-image-embeddings.py. Dieses Skript durchläuft das Verzeichnis mit Ihren Bildern und generiert einzelne Bildeinbettungen. Es erstellt das Dokument mit dem Namen und dem relativen Pfad und speichert es im Elasticsearch-Index „my-image-embeddings“ mit der angegebenen Zuordnung

Verschieben Sie all Ihre Bilder (Fotos) in den Ordner „app/static/images“. Verwenden Sie eine Verzeichnisstruktur mit Unterordnern, um die Bilder übersichtlich zu organisieren. Sobald Sie die Bilder vorbereitet haben, können Sie das Skript mit einigen Parametern ausführen.

Sie benötigen mindestens einige hundert Fotos, um brauchbare Ergebnisse zu erhalten. Mit weniger Bildern erhalten Sie nicht die erwarteten Ergebnisse, da der Raum, in dem Sie suchen, sehr klein ist und die Entfernungen zu den Suchvektoren einander daher sehr ähnlich sind.

Führen Sie das Skript im Ordner „image_embeddings“ aus und ersetzen Sie die Variablen durch Ihre Werte.

$ cd image_embeddings
$ python3 create-image-embeddings.py \
  --es_host='https://image-search.es.europe-west1.gcp.cloud.es.io:443' \
  --es_user='elastic' --es_password=<password> \
  --ca_certs='../app/conf/ess-cloud.cer'

Je nach Anzahl und Größe der Bilder, Ihrer CPU und der vorhandenen Netzwerkverbindung kann dieser Vorgang einige Zeit dauern. Testen Sie den Prozess zuerst mit einer kleinen Anzahl an Bildern, bevor Sie den gesamten Datensatz verarbeiten.
Wenn das Skript abgeschlossen wurde, können Sie mit den Kibana-Entwicklungstools überprüfen, ob der Index „my-image-embeddings“ existiert und die entsprechenden Dokumente enthält.

GET _cat/indices/my-image-embeddings?v

health status index               uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   my-image-embeddings vfA3wOheT1C79R-PceDyXg   1   1       1222            0     24.4mb         12.2mb

Die Dokumente sollten JSON-Objekte enthalten, die ungefähr wie das folgende Beispiel aussehen. Die Objekte enthalten den Bildnamen, die Bild-ID und den relativen Pfad innerhalb des Ordners „images“. Dieser Pfad wird von der Frontend-Anwendung verwendet, um das Bild bei der Suche korrekt anzuzeigen.
Der wichtigste Teil des JSON-Dokuments ist das Objekt „image_embedding“, das den vom CLIP-Modell generierten Dichtevektor enthält. Dieser Vektor wird verwendet, wenn eine Anwendung nach einem Bild oder einem ähnlichen Bild sucht.

{
   "_index": "my-image-embeddings",
   "_id": "_g9ACIUBMEjlQge4tztV",
   "_score": 6.703597,
   "_source": {
     "image_id": "IMG_4032",
     "image_name": "IMG_4032.jpeg",
     "image_embedding": [
       -0.3415695130825043,
       0.1906963288784027,
       .....
       -0.10289803147315979,
       -0.15871885418891907
       ],
     "relative_path": "phone/IMG_4032.jpeg"
   }
}

Bildersuche mit der Flask-Anwendung

Nachdem Sie Ihre Umgebung eingerichtet haben, können Sie im nächsten Schritt nach Bildern suchen, indem Sie eine Textbeschreibung oder ähnliche Bilder angeben. Dazu können Sie die Flask-Anwendung verwenden, die Sie von uns als Machbarkeitsstudie erhalten. Die Webanwendung hat eine einfache Benutzeroberfläche, mit der Sie mühelos nach Bildern suchen können. Sie finden den Prototyp der Flask-Anwendung in diesem GitHub-Repository

Die Hintergrundanwendung führt zwei Aufgaben aus. Wenn Sie die Suchzeichenfolge in das Suchfeld eingeben, wird der Text mit dem Machine-Learning-Endpoint _infer vektorisiert. Anschließend wird die Abfrage mit Ihrem Dichtevektor für den Index my-image-embeddings ausgeführt, der die Vektoren enthält.

Im folgenden Beispiel sehen Sie diese beiden Abfragen. Der erste API-Aufruf verwendet den Endpoint _infer und erhält als Ergebnis einen Dichtevektor zurück.

POST _ml/trained_models/sentence-transformers__clip-vit-b-32-multilingual-v1/deployment/_infer
{
  "docs" : [
    {"text_field": "endless route to the top"}
    ]
}

Die zweite Aufgabe führt die eigentliche Suchabfrage aus und verwendet den Dichtevektor, um Bilder nach ihrer Bewertung sortiert abzurufen.

GET my-image-embeddings/_search
{
  "knn": {
    "field": "image_embedding",
    "k": 5,
    "num_candidates": 10,
    "query_vector": [
    -0.19898493587970734,
    0.1074572503566742,
    -0.05087625980377197,
    ...
    0.08200495690107346,
    -0.07852292060852051
  ]
  },
  "fields": [
    "image_id", "image_name", "relative_path"

  ],
  "_source": false
}

Um die Flask-Anwendung zu starten, navigieren Sie zum Stammordner des Repositorys und konfigurieren Sie die .env-Datei. Die Werte in dieser Konfigurationsdatei sind für die Verbindung zum Elasticsearch-Cluster erforderlich. Geben Sie Werte für die folgenden Variablen ein. Verwenden Sie dieselben Werte wie beim Generieren der Bildeinbettungen.

  • ES_HOST='URL:PORT'
  • ES_USER='elastic'
  • ES_PWD='password'

Führen Sie anschließend die Flask-Anwendung im Hauptordner aus und warten Sie, bis die Anwendung gestartet wurde.

# In the main directory 
$ flask run --port=5001

Wenn die Anwendung gestartet wird, sollte ungefähr die folgende Ausgabe angezeigt werden. Am Ende finden Sie die URL, über die Sie auf die Anwendung zugreifen können.

flask run --port=5001
 * Serving Flask app 'flask-elastic-image-search.py' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5001
Press CTRL+C to quit

Glückwunsch! Ihre Anwendung wird jetzt ausgeführt und ist mit Ihrem Internetbrowser unter http://127.0.0.1:5001 erreichbar.

Navigieren Sie zur Registerkarte für die Bildersuche und geben Sie einen Text ein, der Ihr Bild möglichst gut beschreibt. Verwenden Sie nach Möglichkeit keine Schlüsselwörter oder beschreibende Begriffe.

Im folgenden Beispiel wurde der Text „endloser Weg bis zur Spitze“ eingegeben. Die angezeigten Ergebnisse stammen aus unserem Datensatz. Wenn Ihnen ein bestimmtes Bild im Ergebnissatz besonders gut gefällt, können Sie auf die Schaltfläche daneben klicken, um weitere ähnliche Bilder anzuzeigen. Diesen Vorgang können Sie beliebig oft wiederholen, um einen eigenen Pfad durch den Bilddatensatz zu finden.

Sie können auch ein Bild hochladen, um nach ähnlichen Bildern zu suchen. Die Anwendung konvertiert das Bild in einen Vektor und sucht nach ähnlichen Bildern im Datensatz. Öffnen Sie dazu die dritte Registerkarte Similar Image, laden Sie ein Bild von Ihrem Lokalen Datenträger hoch und klicken Sie auf Search.

Das in Elasticsearch verwendete NLP-Modell (sentence-transformers/clip-ViT-B-32-multilingual-v1) ist mehrsprachig und unterstützt Inferenz in zahlreichen Sprachen. Daher können Sie auch in anderen Sprachen nach Bildern suchen. Überprüfen Sie die Ergebnisse anschließend mit englischem Text.

Vergessen Sie nicht, dass es sich hier um generische Modelle handelt. Diese Modelle sind recht exakt, aber die erhaltenen Ergebnisse hängen stark vom Anwendungsfall und von anderen Faktoren ab. Falls Sie exaktere Ergebnisse brauchen, können Sie entweder ein generisches Modell anpassen oder ein eigenes Modell entwickeln. Das CLIP-Modell dient hier lediglich als Ausgangspunkt.

Code-Zusammenfassung

Sie finden den vollständigen Code im GitHub-Repository. Sehen Sie sich auch den Code in routes.py an. Dort wird die Hauptlogik der Anwendung implementiert. Neben der offensichtlichen Routendefinition sollten Sie sich die Methoden ansehen, in denen die Endpoints „_infer“ und „_search“ definiert werden (infer_trained_model und knn_search_images). Der Code, der die Bildeinbettungen generiert, befindet sich in der Datei create-image-embeddings.py.

Zusammenfassung

Nachdem Sie die Flask-App eingerichtet haben, können Sie problemlos Ihren eigenen Bilderdatensatz durchsuchen! Die Vektorsuche ist nativ in die Elastic Platform integriert, um nicht mit externen Prozessen kommunizieren zu müssen. Sie können jederzeit benutzerdefinierte Einbettungsmodelle entwickeln und einsetzen, die Sie möglicherweise mit PyTorch entwickelt haben.

Die semantische Bildersuche bietet die folgenden Vorteile gegenüber herkömmlichen Ansätzen:

  • Höhere Genauigkeit: Die Vektorähnlichkeit erfasst Kontext und Assoziationen, ohne dazu Metabeschreibungen der Bilder in Textform zu benötigen.
  • Angenehmeres Benutzererlebnis: Beschreiben Sie, wonach Sie suchen, oder laden Sie ein Beispielbild hoch, anstatt raten zu müssen, welche Schlüsselwörter möglicherweise relevant sind.
  • Kategorisierung von Bilddatenbanken: Machen Sie sich keine Sorgen um die Katalogisierung Ihrer Bilder. Die Ähnlichkeitssuche findet relevante Bilder in einer riesigen Bibliothek, ohne sie manuell organisieren zu müssen.

Falls bei Ihrem Anwendungsfall eher Textdaten verwendet werden, erfahren Sie mehr über die Themen semantische Suche und natürliche Sprachverarbeitung für Texte in unseren älteren Blogeinträgen. Für Textdaten bietet eine Kombination aus Vektorähnlichkeiten mit herkömmlicher Schlüsselwortbewertung normalerweise einen optimalen Kompromiss.
Sind Sie bereit loszulegen? Melden Sie sich an für unseren Praxis-Workshop zum Thema Vektorsuche in unserem virtuellen Event Hub und beteiligen Sie sich in unserem Online-Diskussionsforum an der Community.