Apps wie Google Fotos ermöglichen die Suche nach Bildern auf Ihrem Telefon mithilfe von Textabfragen. Das Bemerkenswerte daran ist, dass die App Ihre Bilder nicht anhand ihres Inhalts kennzeichnen muss. Sie können beispielsweise suchen Katze oder Suppe in Ihrer Google Fotos-App und erhalten Sie relevante Ergebnisse, auch wenn Ihren Bildern eine Textbeschreibung fehlt.
Wie schafft die App das? Apps wie diese verstehen den Zusammenhang zwischen der semantischen Beschreibung einer Szene und dem Bildinhalt der Szene selbst. In diesem Weblog werde ich zeigen, wie Sie Ihre eigene Bildersuch-App in Python schreiben können. Wir werden ein vortrainiertes Modell für maschinelles Lernen namens CLIP verwenden, das die von uns benötigte gemeinsame Textual content-/Bilddarstellung bereits versteht. Wir werden auch Streamlit verwenden, um die App bereitzustellen.
Contrastive Language-Picture Pretraining (CLIP) ist ein beliebtes multimodales Textual content/Bild-Modell, das auf einem Artikel von Radford et al. (2021) basiert. Das CLIP-Modell wurde anhand von 400 Millionen Textual content-Bild-Beispielpaaren aus dem Web trainiert. Für unsere App verwenden wir das vorab trainierte Modell, um unsere Textsuchbegriffe mit einer Bilddatenbank abzugleichen.
Streamlit ist ein beliebtes Python-Framework, das auf die Entwicklung von Apps für maschinelles Lernen ausgerichtet ist. Streamlit kümmert sich größtenteils um die ästhetischen Designelemente der App-Entwicklung, sodass wir uns hauptsächlich auf die Aspekte des maschinellen Lernens konzentrieren können.
Die App besteht aus zwei Skripten:
- get_embeddings.py : In diesem Skript kodieren wir Bilder mit dem CLIP-Modell-Bildkodierer in Einbettungen. Einbettungen sind Vektordarstellungen einer Eingabe, die deren beschreibenden Inhalt kodieren.
- app.py : Dies ist die Streamlit-App, die die Bildsuchfunktion implementiert. Für den eingegebenen Suchbegriff werden Texteinbettungen abgerufen und dann mit den Bildeinbettungen verglichen, die im ersten Schritt ausgegeben wurden. Die ähnlichsten Ergebnisse werden dann in einem Rasterformat dargestellt.
Der Code für die get_embeddings.py Das Skript ist unten enthalten. Sie müssen CLIP gemäß den Anweisungen in installieren https://github.com/openai/CLIP.
import os
import clip
import torch
from torch.utils.knowledge import Dataset, DataLoader
import PIL
import pickle
from tqdm import tqdmclass Pictures(Dataset):
"""Pictures dataset"""
def __init__(self, image_list, rework):
"""
Args:
image_list: Checklist of picture paths.
rework : Remodel to be utilized on a pattern.
"""
self.image_list = image_list
self.rework = rework
def __len__(self):
return len(self.image_list)
def __getitem__(self, idx):
image_path = self.image_list[idx]
picture = PIL.Picture.open(image_path)
picture = self.rework(picture)
knowledge = {'picture':picture,
'img_path': image_path}
return knowledge
if __name__ == '__main__':
gadget = "cuda" if torch.cuda.is_available() else "cpu"
mannequin, preprocess = clip.load('ViT-B/32', gadget, jit=False)
print(f'System used: {gadget}')
folder_path = '<Enter folder location along with your photographs right here>'
image_list = [folder_path + file for file in os.listdir(folder_path)]
print('Making an attempt to open photographs...')
cleaned_image_list = []
for image_path in image_list:
attempt:
PIL.Picture.open(image_path)
cleaned_image_list.append(image_path)
besides:
print(f"Failed for {image_path}")
print(f"There are {len(cleaned_image_list)} photographs that may be processed")
dataset = Pictures(cleaned_image_list,preprocess)
dataloader = DataLoader(dataset,
batch_size=256,
shuffle=True)
print("Processing photographs...")
image_paths = []
embeddings = []
for knowledge in tqdm(dataloader):
with torch.no_grad():
X = knowledge['image'].to(gadget)
image_embedding = mannequin.encode_image(X)
img_path = knowledge['img_path']
image_paths.lengthen(img_path)
embeddings.lengthen([torch.Tensor(x).unsqueeze(0).cpu() for x in image_embedding.tolist()])
image_embeddings = dict(zip(image_paths,embeddings))
# save to pickle file for the app
print("Saving picture embeddings")
with open('embeddings.pkl','wb') as f:
pickle.dump(image_embeddings,f)
Der Bilder Klasse erbt von Pytorch Datensatz Klasse und bietet Anweisungen zum Konvertieren eines Bildpfads in einen Pytorch-Tensor. Der Datensatz wird in der Hauptfunktion zum Erstellen eines Pytorch verwendet Datenlader Dies ermöglicht die gemeinsame Verarbeitung von Bildstapeln. Die vektorisierte Natur dieses Vorgangs macht ihn schneller als die Verarbeitung der Bilder einzeln.
Der Code filtert alle Pfade unter dem im angegebenen Verzeichnis heraus Ordnerpfad Variable, um sicherzustellen, dass die Bilder von PIL lesbar sind. Dies hilft auch dabei, alle vernachlässigten Dateien wie .html-Dateien zu entfernen, die Artefakte von Massen-Downloads waren. Nachdem die Einbettungen erstellt wurden, werden sie in einer Pickle-Datei gespeichert, um von der App aufgenommen zu werden.
Der Code für die app.py Das Skript ist unten angegeben.
import streamlit as st
import pandas as pd
import clip
import torch
from sklearn.metrics.pairwise import cosine_similarity
import picklegadget = "cuda" if torch.cuda.is_available() else "cpu"
mannequin, preprocess = clip.load('ViT-B/32', gadget)
# load embeddings from file
with open('embeddings.pkl','rb') as f:
image_embeddings = pickle.load(f)
st.header('Picture Search App')
search_term = 'an image of ' + st.text_input('Search: ')
search_embedding = mannequin.encode_text(clip.tokenize(search_term).to(gadget)).cpu().detach().numpy()
st.sidebar.header('App Settings')
top_number = st.sidebar.slider('Variety of Search Outcomes', min_value=1, max_value=30)
picture_width = st.sidebar.slider('Image Width', min_value=100, max_value=500)
df_rank = pd.DataFrame(columns=['image_path','sim_score'])
for path,embedding in image_embeddings.gadgets():
sim = cosine_similarity(embedding,
search_embedding).flatten().merchandise()
df_rank = pd.concat([df_rank,pd.DataFrame(data=[[path,sim]],columns=['image_path','sim_score'])])
df_rank.reset_index(inplace=True,drop=True)
df_rank.sort_values(by='sim_score',
ascending=False,
inplace=True,
ignore_index=True)
# show code: 3 column view
col1, col2, col3 = st.columns(3)
df_result = df_rank.head(top_number)
for i in vary(top_number):
if i % 3 == 0:
with col1:
st.picture(df_result.loc[i,'image_path'],width=picture_width)
elif i % 3 == 1:
with col2:
st.picture(df_result.loc[i,'image_path'],width=picture_width)
elif i % 3 == 2:
with col3:
st.picture(df_result.loc[i,'image_path'],width=picture_width)
Das App-Skript lädt die Bilderinbettungen, die im vorherigen Schritt gespeichert wurden. Es übernimmt den vom Benutzer eingegebenen Suchbegriff aus der Suchleiste und verwendet ihn, um eine Texteinbettung zu erstellen. Die Texteinbettung wird dann verwendet, um das zu finden top-n ähnliche Bildeinbettungen, die dann in der App angezeigt werden. Sowohl die Anzahl der Suchergebnisse als auch die Bildbreite sind über Schieberegler wählbar.
Eine Demo der Streamlit-App wird unten für eine Suchanfrage von angezeigt Hund auf einem Datensatz von Internetbildern.
Es wird empfohlen, Streamlit im Breitbildmodus auszuführen, der über das Einstellungsmenü oben rechts zugänglich ist.
Die entwickelte App nutzt vorab trainiertes CLIP, um Bilder zu suchen, die einer eingegebenen Textabfrage entsprechen. Es kann jedoch einige spezielle Anwendungen geben, bei denen vorab trainiertes CLIP nicht geeignet ist. Beispielsweise ist das Auffinden bestimmter Automarken aus einer Datenbank mit vielen Autos eine spezielle Aufgabe. Für diese Artwork von Aufgabe müssen wir CLIP an einem beschrifteten, fahrzeugspezifischen Datensatz optimieren. Der zweite Blogbeitrag dieser Reihe zeigt, wie man CLIP an einem domänenspezifischen Datensatz verfeinert.
Radford, Alec, Jong Wook Kim, Chris Hallacy, Aditya Ramesh, Gabriel Goh, Sandhini Agarwal, Girish Sastry et al. „Lernen übertragbarer visueller Modelle aus der Überwachung natürlicher Sprache.“ In Internationale Konferenz zum Thema maschinelles Lernen, S. 8748–8763. PMLR, 2021.