Heim >Technologie-Peripheriegeräte >KI >Erstellen einer Videosuchmaschine mit CLIP
CLIP (Contrastive Language-Image Pre-training) ist eine maschinelle Lerntechnologie, die Bilder und Texte in natürlicher Sprache genau verstehen und klassifizieren kann, was einen tiefgreifenden Einfluss auf die Bild- und Sprachverarbeitung hat und als beliebtes Diffusionsmodell verwendet wird zugrunde liegender Mechanismus von DALL-E. In diesem Beitrag erfahren Sie, wie Sie CLIP zur Unterstützung der Videosuche anpassen.
Dieser Artikel geht nicht auf die technischen Details des CLIP-Modells ein, sondern zeigt eine weitere praktische Anwendung von CLIP (zusätzlich zum Diffusionsmodell).
Zuerst müssen wir wissen: CLIP verwendet einen Bilddecoder und einen Textencoder, um vorherzusagen, welche Bilder im Datensatz mit welchem Text übereinstimmen.
Durch die Verwendung des vorab trainierten CLIP-Modells von Hugging Face können wir ein einfaches, aber leistungsstarkes Modell erstellen Es handelt sich um eine Videosuchmaschine mit natürlichen Sprachfunktionen, für die kein Feature-Engineering erforderlich ist.
Wir müssen die folgende Software verwenden
Python≥= 3.8,ffmpeg,opencv
Es gibt viele Techniken zum Durchsuchen von Videos anhand von Text. Wir können uns eine Suchmaschine so vorstellen, dass sie aus zwei Teilen besteht: Indizierung und Suche.
Die Videoindizierung umfasst typischerweise eine Kombination aus manuellen und maschinellen Prozessen. Menschen verarbeiten Videos vor, indem sie relevante Schlüsselwörter in Titeln, Tags und Beschreibungen hinzufügen, während automatisierte Prozesse visuelle und akustische Funktionen wie Objekterkennung und Audiotranskription extrahieren. Benutzerinteraktionsmetriken und mehr, die aufzeichnen, welche Teile des Videos am relevantesten sind und wie lange sie relevant bleiben. Alle diese Schritte helfen dabei, einen durchsuchbaren Index Ihrer Videoinhalte zu erstellen.
Eine Übersicht über den Indexierungsprozess ist wie folgt
mport scenedetect as sd video_path = '' # path to video on machine video = sd.open_video(video_path) sm = sd.SceneManager() sm.add_detector(sd.ContentDetector(threshold=27.0)) sm.detect_scenes(video) scenes = sm.get_scene_list()
Sampling der Frames der Szene
Dann müssen Sie cv2 verwenden, um das Video zu rahmen.import cv2 cap = cv2.VideoCapture(video_path) every_n = 2 # number of samples per scene scenes_frame_samples = [] for scene_idx in range(len(scenes)): scene_length = abs(scenes[scene_idx][0].frame_num - scenes[scene_idx][1].frame_num) every_n = round(scene_length/no_of_samples) local_samples = [(every_n * n) + scenes[scene_idx][0].frame_num for n in range(3)] scenes_frame_samples.append(local_samples)
from transformers import CLIPProcessor from PIL import Image clip_processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") def clip_embeddings(image): inputs = clip_processor(images=image, return_tensors="pt", padding=True) input_tokens = { k: v for k, v in inputs.items() } return input_tokens['pixel_values'] # ... scene_clip_embeddings = [] # to hold the scene embeddings in the next step for scene_idx in range(len(scenes_frame_samples)): scene_samples = scenes_frame_samples[scene_idx] pixel_tensors = [] # holds all of the clip embeddings for each of the samples for frame_sample in scene_samples: cap.set(1, frame_sample) ret, frame = cap.read() if not ret: print('failed to read', ret, frame_sample, scene_idx, frame) break pil_image = Image.fromarray(frame) clip_pixel_values = clip_embeddings(pil_image) pixel_tensors.append(clip_pixel_values)Der nächste Schritt besteht darin, alle Samples in derselben Szene zu mitteln, was die Dimensionalität des Samples reduzieren und auch das Problem des Rauschens in einem einzelnen Sample lösen kann.
import torch import uuid def save_tensor(t): path = f'/tmp/{uuid.uuid4()}' torch.save(t, path) return path # .. avg_tensor = torch.mean(torch.stack(pixel_tensors), dim=0) scene_clip_embeddings.append(save_tensor(avg_tensor))
Videoszenenindex: Welche Szenen gehören zu einem bestimmten Video
Szeneneinbettungsindex: Spezifisch speichern Szenen Daten
Video-Metadaten-Index: Speichern Sie die Metadaten des Videos.
Wir fügen zunächst alle berechneten Metadaten im Video und die eindeutige Kennung des Videos in den Metadatenindex ein. Dieser Schritt ist bereits fertig und sehr einfach.import leveldb import uuid def insert_video_metadata(videoID, data): b = json.dumps(data) level_instance = leveldb.LevelDB('./dbs/videometadata_index') level_instance.Put(videoID.encode('utf-8'), b.encode('utf-8')) # ... video_id = str(uuid.uuid4()) insert_video_metadata(video_id, { 'VideoURI': video_path, })Erstellen Sie dann einen neuen Eintrag im Szeneneinbettungsindex, um jedes im Video eingebettete Pixel zu speichern, und benötigen Sie außerdem eine eindeutige Kennung, um jede Szene zu identifizieren.
import leveldb import uuid def insert_scene_embeddings(sceneID, data): level_instance = leveldb.LevelDB('./dbs/scene_embedding_index') level_instance.Put(sceneID.encode('utf-8'), data) # ... for f in scene_clip_embeddings: scene_id = str(uuid.uuid4()) with open(f, mode='rb') as file: content = file.read() insert_scene_embeddings(scene_id, content)
import leveldb import uuid def insert_video_scene(videoID, sceneIds): b = ",".join(sceneIds) level_instance = leveldb.LevelDB('./dbs/scene_index') level_instance.Put(videoID.encode('utf-8'), b.encode('utf-8')) # ... scene_ids = [] for f in scene_clip_embeddings: # .. as shown in previous step scene_ids.append(scene_id) scene_embedding_index.insert(scene_id, content) scene_index.insert(video_id, scene_ids)
records = [] level_instance = leveldb.LevelDB('./dbs/scene_index') for k, v in level_instance.RangeIter(): record = (k.decode('utf-8'), str(v.decode('utf-8')).split(',')) records.append(record)Der nächste Schritt erfordert das Sammeln aller in jedem Video vorhandenen Szeneneinbettungstensoren.
import leveldb def get_tensor_by_scene_id(id): level_instance = leveldb.LevelDB('./dbs/scene_embedding_index') b = level_instance.Get(bytes(id,'utf-8')) return BytesIO(b) for r in records: tensors = [get_tensor_by_scene_id(id) for id in r[1]]Nachdem wir alle Tensoren haben, aus denen das Video besteht, können wir es an das Modell übergeben. Die Eingabe in das Modell ist „pixel_values“, ein Tensor, der die Videoszene darstellt.
import torch from transformers import CLIPProcessor, CLIPModel processor = CLIPProcessor.from_pretrained("openai/clip-vit-base-patch32") model = CLIPModel.from_pretrained("openai/clip-vit-base-patch32") inputs = processor(text=text, return_tensors="pt", padding=True) for tensor in tensors: image_tensor = torch.load(tensor) inputs['pixel_values'] = image_tensor outputs = model(**inputs)Greifen Sie dann in der Modellausgabe auf „logits_per_image“ zu, um die Ausgabe des Modells zu erhalten. Logits sind im Wesentlichen die rohen, nicht normalisierten Vorhersagen des Netzwerks. Da wir nur eine Textzeichenfolge und einen Tensor bereitstellen, der die Szene im Video darstellt, ist die Struktur des Logits eine einwertige Vorhersage.
logits_per_image = outputs.logits_per_image probs = logits_per_image.squeeze() prob_for_tensor = probs.item()Addieren Sie die Wahrscheinlichkeiten für jede Iteration und dividieren Sie sie durch die Gesamtzahl der Tensoren am Ende der Operation, um die durchschnittliche Wahrscheinlichkeit des Videos zu erhalten.
def clip_scenes_avg(tensors, text): avg_sum = 0.0 for tensor in tensors: # ... previous code snippets probs = probs.item() avg_sum += probs.item() return avg_sum / len(tensors)
最后在得到每个视频的概率并对概率进行排序后,返回请求的搜索结果数目。
import leveldb import json top_n = 1 # number of search results we want back def video_metadata_by_id(id): level_instance = leveldb.LevelDB('./dbs/videometadata_index') b = level_instance.Get(bytes(id,'utf-8')) return json.loads(b.decode('utf-8')) results = [] for r in records: # .. collect scene tensors # r[0]: video id return (clip_scenes_avg, r[0]) sorted = list(results) sorted.sort(key=lambda x: x[0], reverse=True) results = [] for s in sorted[:top_n]: data = video_metadata_by_id(s[1]) results.append({ 'video_id': s[1], 'score': s[0], 'video_uri': data['VideoURI'] })
就是这样!现在就可以输入一些视频并测试搜索结果。
通过CLIP可以轻松地创建一个频搜索引擎。使用预训练的CLIP模型和谷歌的LevelDB,我们可以对视频进行索引和处理,并使用自然语言输入进行搜索。通过这个搜索引擎使用户可以轻松地找到相关的视频,最主要的是我们并不需要大量的预处理或特征工程。
那么我们还能有什么改进呢?
可以在这里找到本文的代码:https://github.com/GuyARoss/CLIP-video-search/tree/article-01。
以及这个修改版本:https://github.com/GuyARoss/CLIP-video-search。
Das obige ist der detaillierte Inhalt vonErstellen einer Videosuchmaschine mit CLIP. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!